PhpStorm 2016.2 find and replace multiline text - php

In PhpStorm 2016.2 I have a new project that has been inherited and [badly] needs updating.
There are many pages each with opening line like so (example):
<?
include ("/inc/db.php");
I need to replace this line with several lines such as:
<?php
include "siteheader.php";
require "class.myclass.inc.php";
$dataBase = new DbObj();
I have previously simply copy and pasted multiline code into the PhpStorm search/replace function and that's (usually but not always) returned the correct changes, although they're all squished into single lines, making them harder to read (EOL characters are removed).
In this instance am looking specifically at the "replace in path" function as I need to apply this change to many pages.
I have Read the manual but can see no option for this. I think I could possibly use a Regular Expression but this would not be ideal (escapings etc.).
I have also looked but not found a suitable plugin from the PhpStorm Plugin Repository.
Is there a way of searching and/or replacing multiline text in path in PhpStorm 2016.2?
Cheers

There is no easy to use multi-line search or replace across multiple files (Find/Replace in Path functionality) unfortunately.
Right now you have to use Regex option for that -- that's the only option that works.
Watch these tickets (star/vote/comment) to get notified on any progress in this regard.
https://youtrack.jetbrains.com/issue/IDEA-69435
https://youtrack.jetbrains.com/issue/IDEA-61925
https://youtrack.jetbrains.com/issue/IDEA-145720
Manually making regex-compatible text can be quite problematic .. therefore you might use this few-steps trick:
Type your new text in one file to start with
Select such text and invoke Replace in Path... dialog -- with Regex option pre-selected it should automatically escape your selection to be regex-compatible
Copy that already-escaped text somewhere (just Clipboard should be enough)
Close dialog and go back to original file
Select text you want to replace and invoke Replace in Path... dialog -- it will have your initial text already filled in and regex compatible
Paste previously copied escaped text into Replace field
Execute find/replacement
On related note: https://stackoverflow.com/a/38672886/783119

You can do multiline Find&Replace with Regex option turned on
Find:
<\?\ninclude \("/inc/db\.php"\);
Replace:
<?php\ninclude "siteheader.php"; \nrequire "class.myclass.inc.php"; \n\$dataBase = new DbObj();
As you can see you need to do some additional work to escape some special characters and put \n instead of new lines, but it works. I've just checked.
P.S.
Indeed, it was possible to simply paste multiline text in previous versions, but it's not possible anymore. ;-(

Type Alt+Enter to add a new line in either the "search" or the "replace" field.

On a Mac:
open the 'Find' or 'Replace' tool, click into the text area and press the following keys once for every new line you want to create:
⌘ + 'Shift' + 'Enter'

Besides the suggestions on how to use regex for multiline, in case you want to match two pieces of code with arbitrary lines in the middle, you can use [\s\S]* instead of [\n.]* (which doesn't have the expected result). Example:
//you can match the $result-related code using `\$result([\s\S]*)while`
$result = DB::exec($query);
//blabla
//something else
while ($row = $result->fetch()) {

\s works as expected to match all whitespaces and newlines.
In my case I wanted to find switch ... case ... continue; syntax, so switch(\s|.)*continue worked as expected

Related

Custom php Hide programmer's comments from public view

When we create a html page comments like
<!-- Comment 1 -->
or inside php
// Comment2
are obvious from a right click of the page - Show code
How can i prevent that ?
Hiding the comments inside is the answer.. Thanks everyone.
Html comments will show on the HTML page but as long as you include your PHP comments in the <?php tag they won't show to the user
To leave html comments are normal if you check amazon.com's code you will see all the html comments but none php or whatever server lang they use so don't worry about html comments just don't include stupid stuff like your admin password or some revealing database schema stuff in the html comments.
if you still want to remove all the comments even html(vscode):
Easy way:
Open extensions (ctrl-shift-x) * type in remove comments in the
search box. * Install the top pick and read instructions.
Hard way: * search replace(ctrl-h) * toggle regex on (alt-r). * Learn some regular expressions! https://docs.rs/regex/0.2.5/regex/#syntax
A simple //.* will match all single line comments (and more ;D).
#.* could be used to match python comments. And /\*[\s\S\n]*\*/
matches block comments. And you can combine them as well:
//.*|/\*[\s\S\n]*\*/ (| in regex means "or", . means any
character, * means "0 or more" and indicates how many characters to
match, therefore .* means all characters until the end of the line
(or until the next matching rule))
Of course with caveats, such as urls (https://...) has double
slashes and will match that first rule, and god knows where there are
# in code that will match that python-rule. So some
reading/adjusting has to be done!
Once you start fiddling with your regexes it can take a lifetime to
get them perfect, so be careful and go the easy route if you are short
on time, but knowing some simple regex by heart will do you good,
since regular expressions are usable almost everywhere.
From https://stackoverflow.com/a/50575194/17239314

Targeting specific PHP tag with regex

All my wordpress websites have recently been hacked, and a very long PHP line has been added on top of all PHP files.
It looks like that (juste a sample of the entire code)
<?php $gqmtlkp = '~ x24<!%o:!>! x242178}527}88:}35csboe))1/35.)1/14+9**-)1/2986+7452]88]5]48]32M3]317]445]212]445]43]321]y]252]18y]#>q%
The problem is that code is generated and is different in all files. But I noticed that every code contains
explode(chr((729-609))
Can someone help me with building a regex line, that will target first php tag (optional) containing : (numbers vary)
explode(chr((xxx-xxx))
so that I can automatically remove it in every files ?
Thanks a lot for your help
Based on my understanding of your request you're looking to escape the following format: <?php(optional) explode(chr((xxx-xxx))) <- your sample was missing a third closing paranthesis for explode() function so I added it. If that's not right then just remove the last \) portion.
Try this: /(\<\?php)? explode\(chr\(\([0-9]{3,3}-[0-9]{3,3}\)\)\)/
Not sure if space after optional first php tag is necessary. You can adjust it going from there.

What is a regex to use in Notepad++ to copy only the needed parts?

I am using Notepad++ and I have a task to copy some attributes from a huge list as explained below:
this is just a tiny part of my list
[{"model_id":"58781","model_make_id":"mini","model_name":"Roadster","IntColors":[]}]
and I want to copy or leave only the "58781", and the "mini", and the "Roadster", and so on from the list.
So at the end my file (or the new one) will be
[{"58781","mini","Roadster",}]
of if it is easier leave the : also like [{:"58781",:"mini",:"Roadster",}]
What regex should I use to do this?
Thank you
you can use this search/replace:
search: (?<=[{,])"[^"]+":|\[\]
replace: nothing

Matching all three kinds of PHP comments with a regular expression

I need to match all three types of comments that PHP might have:
# Single line comment
// Single line comment
/* Multi-line comments */
 
/**
* And all of its possible variations
*/
Something I should mention: I am doing this in order to be able to recognize if a PHP closing tag (?>) is inside a comment or not. If it is then ignore it, and if not then make it count as one. This is going to be used inside an XML document in order to improve Sublime Text's recognition of the closing tag (because it's driving me nuts!). I tried to achieve this a couple of hours, but I wasn't able. How can I translate for it to work with XML?
So if you could also include the if-then-else login I would really appreciate it. BTW, I really need it to be in pure regular expression expression, no language features or anything. :)
Like Eicon reminded me, I need all of them to be able to match at the start of the line, or at the end of a piece of code, so I also need the following with all of them:
<?php
echo 'something'; # this is a comment
?>
Parsing a programming language seems too much for regexes to do. You should probably look for a PHP parser.
But these would be the regexes you are looking for. I assume for all of them that you use the DOTALL or SINGLELINE option (although the first two would work without it as well):
~#[^\r\n]*~
~//[^\r\n]*~
~/\*.*?\*/~s
Note that any of these will cause problems, if the comment-delimiting characters appear in a string or somewhere else, where they do not actually open a comment.
You can also combine all of these into one regex:
~(?:#|//)[^\r\n]*|/\*.*?\*/~s
If you use some tool or language that does not require delimiters (like Java or C#), remove those ~. In this case you will also have to apply the DOTALL option differently. But without knowing where you are going to use this, I cannot tell you how.
If you cannot/do not want to set the DOTALL option, this would be equivalent (I also left out the delimiters to give an example):
(?:#|//)[^\r\n]*|/\*[\s\S]*?\*/
See here for a working demo.
Now if you also want to capture the contents of the comments in a group, then you could do this
(?|(?:#|//)([^\r\n]*)|/\*([\s\S]*?)\*/)
Regardless of the type of comment, the comments content (without the syntax delimiters) will be found in capture 1.
Another working demo.
Single-line comments
singleLineComment = /'[^']*'|"[^"]*"|((?:#|\/\/).*$)/gm
With this regex you have to replace (or remove) everything that was captured by ((?:#|\/\/).*$). This regex will ignore contents of strings that would look like comments (e.g. $x = "You are the #1"; or $y = "You can start comments with // or # in PHP, but I'm a code string";)
Multiline comments
multilineComment = /^\s*\/\*\*?[^!][.\s\t\S\n\r]*?\*\//gm

Setup a shortcut to replace easily selected strings in VIM

I have a lot of php/html files with many strings that should be internationalized with gettext.
Therefore, I have to go through each file, spot the "message" strings and replace each one by
<?= _("<my string>") ?>
I use vim and would like to setup a shortcut (map) to do it easily in insert mode (With CtrlR for instance).
Do you know how to achieve that ?
I would use Tim Pope's wonderful surround plugin to accomplish this.
Add the following to your ~/.vim/after/ftplugin/php.vim file:
let b:surround_{char2nr('_')} = "<?= _(\"\r\") ?>"
Now you can select some via visual mode then surround. e.g vitS_
If you are in insert mode you can surround text via <c-s>_ and you cursor will be inserted in between the double quotes.
As a bonus if you want to do the delete the surrounding <?= _("<text here>") ?> and only leave <text here> you can add the following to your ~/.vim/after/ftplugin/php.vim as well:
nmap <buffer> <silent> ds_ ds<dt(%df?[(xds"
Tim Pope has many great plugins I highly suggest you take a look some of them.
For more help see:
:h surround
:h surround-customizing
:h after-directory
:h curly-braces-names
:h b:var
My guess is that you want the original message to actually be the input to the _() function, do you not?
The best thing I can think for you to do is to use macros. If I were doing this I would probably do something like record a macro #1 for one-word "messages" (that need to be replaced), #2 for two-word messages, #3 for 3 and so on. Then I could just skim or search through the documents and type #1 on the start of any one-word message like one
to replace it with <?= _("one") ?>. I would use #2 on a message like two words to transform it to <?= _("two words") /> and so forth.
To create/record the macro for one-word messages, #1, type these keys, preferably on the start of a one-word message:
q1i<?= _("<Esc>eli") ?><Esc>q
q 1 i < ? = Space _ ( " Esc e l i " ) Space ? > Esc q
The macros for more words can be created very similarly, just add additional es for more words. So for #2, type this:
q1i<?= _("<Esc>eeli") ?><Esc>q
q 1 i < ? = Space _ ( " Esc e e l i " ) Space ? > Esc q
In the case of really long messages, I would probably use an open and close macro. The open one would place <?= _(" wherever I had my cursor and the close one would put ") ?> wherever I had my cursor.
If you want to surround this strings manually and if your message does not contain ", then you can (after putting cursor somewhere inside the message) do the following once:
qaf"a)<Esc>2F"i_(<Esc>q
(press real escape for <Esc>) then, after putting the cursor on the next message, repeat this by
#a
(if you don’t like a, replace it with another latin lowercase letter here and above after q). If you still want to have a mapping:
:nnoremap <C-r> f"a)<Esc>2F"i_(<Esc>
. This time <Esc> is literally <, E, s, c, >.
First is using macros and they are quite handy as defining a mapping is more to type. Depending on 'viminfo' option they may be even saved across vim sessions, but you should not really rely on this, so if you want something persistent use the mapping putting it in the vimrc.
Update: If you don’t have <? "message" ?> which I assumed, but instead got <tag>message</tag>, you can do the following:
:nnoremap <C-r> f<i") ?><Esc>F>a<? _("<Esc>
. Note that this time message should not contain < or >.
Regex
Vim is very capable of handling tasks like this with ease. Without a before and after example it's difficult to give you a precise solution, but I'll make a hypothetical one to demonstrate some of vim's power. Say you wanted to change any text inside a <span> tag to be executed by a PHP function. I might have a span tag like this:
<span>I need this text and all other span tags run through PHP!</span>
Probably the easiest way to get the job done is using regex. For example:
:%s/<span>\([^<]*\)<\/span>/<?= _("\1") ?>/g
This finds all span tags in the document and replaces them appropriately. You can even run this on multiple files (see :help bufdo). However, regex can be difficult for some people at first and many haven't taken the time to learn it well. Another option might look like this:
CTRL-R
/<span><cr>f>lct<<?= _("<C-r>"") ?><esc>
Step by step
/<span><cr> - search for opening span tags
f>l - move cursor to the character after the opening span tag
ct< - change the text until the next < character
<?= _("<C-r>"") ?> - put in what we want. The <C-r>" (as you referred to) will put in the contents of our unnamed register ", which in this case is the text we executed ct< on a minute ago.
<esc> - return to normal mode
Macro this
This might be useful to use as a macro. If so, just do the exact same thing with a macro around it...
qq/<span><cr>f>lct<<?= _("<C-r>"") ?><esc>q
Now you can execute #q to do the same thing to the next <span> tag. After you've used #q once you can also use ## or even 100#q to do it 100 times.

Categories