vs code replace two different sides of something - regex

suppose I have code that looks something like
myFunc(someInput);
and suppose I run this function in many different places, on many different inputs (someInput could be various things, I need to perserve whatever it is).
All the sudden I realize I need to perform another function on the input. So I would like to replace every instance with
myFunc(nutherFunc(someInput));
I could run a replace of myFunc( with myFunc(nutherFunc( but would have to manually close the nutherFunc call everywhere. is there a way, using regex or otherwise, that I can replace myFunc(nutherFunc( AND )) while preservint the input?
Said another way, can I say "replace these two character sets but keep what is in between them"?

You can use a regex with a capture group to accomplish this. I'd recommend
myFunc\( # match the literal characters "myFunc(" (We have to escape the paren)
(\w+) # capture group so we can refer to the argument of `myFunc` in the replacement
\) # a literal close paren
with a replacement of
myFunc(notherFunc($1))
Where the $1 represents the group that was captured between parens.
Here's a video: https://clip.brianschiller.com/wjuWYgc-2019-12-17-replace.mp4

Related

Regex search and replace except for specific word

I'm trying to search and replace some strings in my code with RegEx as follows:
replacing self.word with self.indices['word']
So for example, replace:
self.example
with
self.indices['example']
But it should work for all words, not just 'example'.
So the RegEx needed for this probably doesn't need the actual word in it.
It should actually just replace everything but the word itself.
What I tried is the following:
self.(.*?)
It works for searching all the strings that match 'self.' but when I want to change it I lose the word like 'example' so I can't change it to self.indices['example'].
What you need to do is a substitution using capturing groups. Depending on the language used some of the syntax might be slightly different but in general you would want something like this:
self\.([^\s]+)
replace with:
self.indices['\1']
https://regex101.com/r/R3xFZB/1
We are using the parans to caputre what is after self. and in the replace putting that captured data into \1 which is the first (and in this case) only captured group. For some languages you might need $1 or \\1 for the substitution variable.
As with most regexes this can be done many different ways using look arounds, etc. but I think for somebody new this is easy to read, understand and maintain. The comment #wnull made has a more proper regex leveraging a look behind that should also do the trick :)

VSCode Regex Find/Replace In Files: can't get a numbered capturing group followed by numbers to work out

I have a need to replace this:
fixed variable 123
with this:
fixed variable 234
In VSCode this matches fine:
fixed(.*)123
I can't find any way to make it put the capture in the output if a number follows:
fixed$1234
fixed${1}234
But the find replace window just looks like this:
I read that VSCode uses rust flavoured rexes.. Here indicates ${1}234 should work, but VSCode just puts it in the output..
Tried named capture in a style according to here
fixed(?P<n>.*)123 //"invalid regular expression" error
VSCode doesn't seem to understand ${1}:
ps; I appreciate I could hack it in the contrived example with
FIND: fixed (.*) 123
REPL: fixed $1 234
And this does work in vscode:
but not all my data consistently has the same character before the number
After a lot of investigation by myself and #Wiktor we discovered a workaround for this apparent bug in vscode's search (aka find across files) and replace functionality in the specific case where the replace would have a single capture group followed by digits, like
$1234 where the intent is to replace with capture group 1 $1 followed by 234 or any digits. But $1234 is the actual undesired replaced output.
[This works fine in the find/replace widget for the current file but not in the find/search across files.]
There are (at least) two workarounds. Using two consecutive groups, like $1$2234 works properly as does $1$`234 (or precede with the $backtick).
So you could create a sham capture group as in (.*?)()(\d{3}) where capture group 2 has nothing in it just to get 2 consecutive capture groups in the replace or
use your intial search regex (.*?)(\d{3}) and then use $` just before or after your "real" capture group $1.
OP has filed an issue https://github.com/microsoft/vscode/issues/102221
Oddly, I just discovered that replacing with a single digit like $11 works fine but as soon as you add two or more it fails, so $112 fails.
I'd like to share some more insights and my reasoning when I searched for a workaround.
Main workaround idea is using two consecutive backreferences in the replacement.
I tried all backreference syntax described at Replacement Strings Reference: Matched Text and Backreferences. It appeared that none of \g<1>, \g{1}, ${1}, $<1>, $+{1}, etc. work. However, there are some other backreferences, like $' (inserts the portion of the string that follows the matched substring) or $` (inserts the portion of the string that precedes the matched substring). However, these two backreferences do not work in VS Code file search and replace feature, they do not insert any text when used in the replacement pattern.
So, we may use $` or $' as empty placeholders in the replacement pattern.
Find What:      fix(.*?)123
Replace With:
fix$'$1234
fix$`$1234
Or, as in my preliminary test, already provided in Mark's answer, a "technical" capturing group matching an empty string, (), can be introduced into the pattern so that a backreference to that group can be used as a "guard" before the subsequent "meaningful" backreference:
Find What: fixed()(.*)123 (see () in the pattern that can be referred to using $1)
Replace With: fixed$1$2234
Here, $1 is a "guard" placeholder allowing correct parsing of $2 backreference.
Side note about named capturing groups
Named capturing groups are supported, but you should use .NET/PCRE/Java named capturing group syntax, (?<name>...). Unfortunately, the none of the known named backreferences work replacement pattern. I tried $+{name} Boost/Perl syntax, $<name>, ${name}, none work.
Conclusion
So, there are several issues here that need to be addressed:
We need an unambiguous numbered backerence syntax (\g<1>, ${1}, or $<1>)
We need to make sure $' or $` work as expected or are parsed as literal text (same as $_ (used to include the entire input string in the replacement string) or $+ (used to insert the text matched by the highest-numbered capturing group that actually participated in the match) backreferences that are not recognized by Visual Studio Code file search and replace feature), current behavior when they do not insert any text is rather undefined
We need to introduce named backreference syntax (like \g<name> or ${name}).

How can I use Regex to find if I used the same character in multiple different locations?

So I am looking through different numbers that have different delimiters, and I want to find all numbers that have the same delimiter.
Basically, I want the following
123+456+7890 // MATCH
123-456-7890 // MATCH
123.456.7890 // MATCH
123+456-7890 // FAILURE
My current regex I plan to use was
\d{3}[+-.]\d{3}[+-.]\d{4}
However, it would match number sequences that have the different delimiters. I don't want to use one big huge OR for something like this because the real life equivalent has many more characters that could fit there.
Is there a way to match the same character in multiple locations?
You can use a captured group and a back-reference to ensure same delimiter is used again.
^\d{3}([+.-])\d{3}\1\d{4}$
([+.-]) here we capture delimiter in group #1
\1 Here we are using back-reference of same delimiter
RegEx Demo
You can use a back reference like this:
\d{3}([+.-])\d{3}\1\d{4}
The first operator that is matched [+-.] is kept inside a capturing group so that it can be referenced later.
\1 is a backreference to the first capturing group which in this case is [+-.] so it will ensure that the operator is same as the previous one.
Regex 101 Demo
You can read more about backreferences here

Regex to find two words on the page

I'm trying to find all pages which contain words "text1" and "text2".
My regex:
text1(.|\n)*text2
it doesn't work..
If your IDE supports the s (single-line) flag (so the . character can match newlines), you can search for your items with:
(text1).*(text2)|\2.*\1
Example with s flag
If the IDE does not support the s flag, you will need to use [\s\S] in place of .:
(text1)[\s\S]*(text2)|\2[\s\S]*\1
Example with [\s\S]
Some languages use $1 and $2 in place of \1 and \2, so you may need to change that.
EDIT:
Alternately, if you want to simply match that a file contains both strings (but not actually select anything), you can utilize look-aheads:
(?s)^(?=.*?text1)(?=.*?text2)
This doesn't care about the order (or number) of the arguments, and for each additional text that you want to search for, you simply append another (?=.*?text_here). This approach is nice, since you can even include regex instead of just plain strings.
text0[\s\S]*text1
Try this.This should do it for you.
What this does is match all including multiline .similar to having .*? with s flag.
\s takes care of spaces,newlines,tabs
\S takes care any non space character.
If you want the regex to match over several lines I would try:
text1[\w\W]*text2
Using . is not a good choice, because it usually doesn't match over multiple lines. Also, for matching single characters I think using square brackets is more idiomatic than using ( ... | ... )
If you want the match to be order-independent then use this:
(?:text1[\w\W]*text2)|(?:text2[\w\W]*text1)
Adding a response for IntelliJ
Building on #OnlineCop's answer, to swap the order of two expressions in IntelliJ,you would style the search as in the accepted response, but since IntelliJ doesn't allow a one-line version, you have to put the replace statement in a separate field. Also, IntelliJ uses $ to identify expressions instead of \.
For example, I tend to put my nulls at the end of my comparisons, but some people prefer it otherwise. So, to keep things consistent at work, I used this regex pattern to swap the order of my comparisons:
Notice that IntelliJ shows in a tooltip what the result of the replacement will be.
For me works text1*{0,}(text2){0,}.
With {0,} you can decide to get your keyword zero or more times OR you set {1,x} to get your keyword 1 or x-times (how often you want).

Replace while keeping certain "words" in vi/vim

For example, if I have $asd['word_123'] and I wanted to replace it with $this->line('word_123'), keeping the 'word_123'. How could I do that?
By using this:
%s/asd\[\'.*\'\]/this->line('.*')/g
I will not be able to keep the wording in between. Please enlighten me.
Using regex, you could do something like :%s/\$asd\['\([^']*\)'\]/$this->line('\1')/g
Step by step:
%s - substitute on the whole file
\$asd\[' - match "$asd['". Notice the $ and [ need to be escaped since these have special meaning in regex.
\([^']*\) - the \( \) can be used to select what's called an "atom" so that you can use it in the replacement. The [^'] means anything that is not a ', and * means match 0 or more of them.
'\] - finishes our match.
$this->line('\1') - replaces with what we want, and \1 replaces with our matched atom from before.
g - do this for multiple matches on each line.
Alternative (macro)
Instead of regex you could also use a macro. For example,
qq/\$asd<Enter>ct'$this->line(<Esc>f]r)q
then #q as many times as you need. You can also ## after you've used #q once, or you can 80#q if you want to use it 80 times.
Alternative (:norm)
In some cases, using :norm may be the best option. For example, if you have a short block of code and you're matching a unique character or position. If you know that "$" only appears in "$asd" for a particular block of code you could visually select it and
:norm $T$ct'this->line(<C-v><Esc>f]r)<Enter>
For a discourse on using :norm more effectively, read :help :norm and this reddit post.
Try using
:%s/\$asd\[\'\([^\']\+\)\'\]/$this->line('\1')/g