How do I need to escape search string in vim? - regex

I need to search and replace this:
ExecIf($["${debug}" = "1"]?NoOp
with this:
GoSub(chanlog,s,1(1,[${CHANNEL}]
I can't seem to do it in vim, and I'm not sure what needs to be escaped, as nothing I've tried works.

If you want to change a long string with lots of punctuation characters, and it's an exact match (you don't want any of them to be treated as regex syntax) you can use the nomagic option, to have the search pattern interpreted as a literal string.
:set nomagic
:%s/ExecIf($["${debug}" = "1"]?NoOp/GoSub(chanlog,s,1(1,[${CHANNEL}]/
:set magic
You still have to watch out for the delimiters (the slashes of the s/// command) but you can use any character for that, it doesn't have to be a slash, so when you have something like this and there are slashes in the search or replace string, just pick something else, like s#foo#bar# or s:bar:baz:.

If you're having problems with which characters to escape in a vim substitution (:s//), remember the nomagic concept, and in particular the nomagic version of a substitute: :snomagic// or :sno//. nomagic means: interpret each character literally.
So this should work without worrying about escaping characters in the substitution:
:sno/ExecIf($["${debug}" = "1"]?NoOp/GoSub(chanlog,s,1(1, [${CHANNEL}]/
Get to know magic vs. nomagic, :sno//, and \v, \V:
:help magic
The nomagic version of a search for your string uses \V:
/\VExecIf($["${debug}" = "1"]?NoOp

you have to escape the [] and the spaces:
:s/ExecIf($\["${debug}"\ =\ "1"\]?NoOp/GoSub(chanlog,s,1(1,\[${CHANNEL}\]/
just a bit trial and error

Related

How do I only find newlines in a Regex?

I have a regex which finds newlines encoded in strings as \n (not the actual newline character), but it also finds encoded escaped newlines (\\n), like before the word "anything" in the string below.
var rg = '/(\\n)/g'
var str = 'so you can do pretty much \\nanything you want with it. \n\nAt runtime Carota has'
How can I find all of the newlines and none of the escaped newlines?
Here is a link with an example. https://regexr.com/4fna7
You probably want a negative lookbehind. This is used to look for characters behind text, but not include it in the capture.
Your rewritten regex would look like:
(?<!\\)(\\n)
One way to do this is to begin with a negated character class to ensure you do not pick up the double backslash:
var rg = '/[^\\](\\n)/g'
var str = 'so you can do pretty much \\nanything you want with it. \n\nAt runtime Carota has'
I'm assuming you're using JavaScript. In which case you can simply use the Regex literals like so:
/\n/
That would match all newline characters. If you can't use a Regex literal, JS also offers a constructor which takes a string
new RegExp('\\n')
In order to match the \\n you will need to escape the backslash:
/\\n|\n/
with constructor:
new RegExp('\\\\n|\\n')
Hope that helps.

Trouble converting regex

This regex:
"REGION\\((.*?)\\)(.*?)END_REGION\\((.*?)\\)"
currently finds this info:
REGION(Test) my user typed this
END_REGION(Test)
I need it to instead find this info:
#region REGION my user typed this
#endregion END_REGION
I have tried:
"#region\\ (.*?)\\\n(.*?)#endregion\\ (.*?)\\\n"
It tells me that the pattern assignment has failed. Can someone please explain what I am doing wrong? I am new to Regex.
It seems the issue lies in the multiline \n. My recommendation is to use the modifier s to avoid multiline complexities like:
/#region\ \(.*?\)(.*?)\s#endregion\s\(.*?\)/s
Online Demo
s modifier "single line" makes the . to match all characters, including line breaks.
Try this:
#region(.*)?\n(.*)?#endregion(.*)?
This works for me when testing here: http://regexpal.com/
When using your original text and regex, the only thing that threw it off is that I did not have a new line at the end because your sample text didn't have one.
Constructing this regex doesn't fail using boost, even if you use the expanded modifier.
Your string to the compiler:
"#region\\ (.*?)\\\n(.*?)#endregion\\ (.*?)\\\n"
After parsed by compiler:
#region\ (.*?)\\n(.*?)#endregion\ (.*?)\\n
It looks like you have one too many escapes on the newline.
if you present the regex as expanded to boost, an un-escaped pound sign # is interpreted as a comment.
In that case, you need to escape the pound sign.
\#region\ (.*?)\\n(.*?)\#endregion\ (.*?)\\n
If you don't use the expanded modifier, then you don't need to escape the space characters.
Taking that tack, you can remove the escape on the space's, and fixing up the newline escapes, it looks like this raw (what gets passed to regex engine):
#region (.*?)\n(.*?)#endregion (.*?)\n
And like this as a source code string:
"#region (.*?)\\n(.*?)#endregion (.*?)\\n"
Your regular expression has an extra backslash when escaping the newline sequence \\\n, use \\s* instead. Also for the last capturing group you can use a greedy quantifier instead and remove the newline sequence.
#region\\ (.*?)\\s*(.*?)#endregion\\ (.*)
Compiled Demo

RegEx to match string between delimiters or at the beginning or end

I am processing a CSV file and want to search and replace strings as long as it is an exact match in the column. For example:
xxx,Apple,Green Apple,xxx,xxx
Apple,xxx,xxx,Apple,xxx
xxx,xxx,Fruit/Apple,xxx,Apple
I want to replace 'Apple' if it is the EXACT value in the column (if it is contained in text within another column, I do not want to replace). I cannot see how to do this with a single expression (maybe not possible?).
The desired output is:
xxx,GRAPE,Green Apple,xxx,xxx
GRAPE,xxx,xxx,GRAPE,xxx
xxx,xxx,Fruit/Apple,xxx,GRAPE
So the expression I want is: match the beginning of input OR a comma, followed by desired string, followed by a comma OR the end of input.
You cannot put ^ or $ in character classes, so I tried \A and \Z but that didn't work.
([\A,])Apple([\Z,])
This didn't work, sadly. Can I do this with one regular expression? Seems like this would be a common enough problem.
It will depend on your language, but if the one you use supports lookarounds, then you would use something like this:
(?<=,|^)Apple(?=,|$)
Replace with GRAPE.
Otherwise, you will have to put back the commas:
(^|,)Apple(,|$)
Or
(\A|,)Apple(,|\Z)
And replace with:
\1GRAPE\2
Or
$1GRAPE$2
Depending on what's supported.
The above are raw regex (and replacement) strings. Escape as necessary.
Note: The disadvatage with the latter solution is that it will not work on strings like:
xxx,Apple,Apple,xxx,xxx
Since the comma after the first Apple got consumed. You'd have to call the regex replacement at most twice if you have such cases.
Oh, and I forgot to mention, you can have some 'hybrids' since some language have different levels of support for lookbehinds (in all the below ^ and \A, $ and \Z, \1 and $1 are interchangeable, just so I don't make it longer than it already is):
(?:(?<=,)|(?<=^))Apple(?=,|$)
For those where lookbehinds cannot be of variable width, replace with GRAPE.
(^|,)Apple(?=,|$)
And the above one for where lookaheads are supported but not lookbehinds. Replace with \1Apple.
This does as you wish:
Find what: (^|,)(?:Apple)(,|$)
Replace with: $1GRAPE$2
This works on regex101, in all flavors.
http://regex101.com/r/iP6dZ8
I wanted to share my original work-around (before the other answers), though it feels like more of a hack.
I simply prepend and append a comma on the string before doing the simpler:
/,Apple,/,GRAPE,/g
then cut off the first and last character.
PHP looks like:
$line = substr(preg_replace($search, $replace, ','.$line.','), 1, -1);
This still suffers from the problem of consecutive columns (e.g. ",Apple,Apple,").

Replacing multiple string Replace() with a single Regex.Replace()

if I'm doing something like that:
someString.Replace("abc","").Replace("def","").Replace(#"c:\Windows","")
How can I replace that with
Regex.Replace(someString," \\here I don't know what the pattern should be")
I've tried this:
Regex.Replace(someString, #"(?:abc|def|c:\Windows)")
but it didn't work
UPD...
The problem is when I pass the path like that
Regex.Replace(someString, #"(?:abc|def|"+aPath+")")
`But it didnt work` doesn't say much helpfull!
Try this:
someString = Regex.Replace(someString, #"(?:abc|def|ghi|c:\\Windows)", "")
It did work when I tried it. I thinks the reason why your code doesn't work is because you forgot the replacement string and you have to escape the backslash in the path.
I'm assuming the thing that "didn't work" is your C:\windows replacement. You need
someString = Regex.Replace(someString, #"(?:abc|def|C:\\windows)","");
The problem is you need to escape your backslash. An unescaped backslash has meaning in regex. In particular, in this case, \W actually matches any non-alphanumeric character.
Edit to escape an any arbitrary string, you can use Regex.Escape(yourString);

Perl regex with exclamation marks

How do you define/explain this Perl regex:
$para =~ s!//!/!g;
I know the s means search, and g means global (search), but not sure how the exclamation marks ! and extra slashes / fit in (as I thought the pattern would look more like s/abc/def/g).
Perl's regex operators s, m and tr ( thought it's not really a regex operator ) allow you to use any symbol as your delimiter.
What this means is that you don't have to use / you could use, like in your question !
# the regex
s!//!/!g
means search and replace all instances of '//' with '/'
you could write the same thing as
s/\/\//\/g
or
s#//#/#g
or
s{//}{/}g
if you really wanted but as you can see the first one, with all the backslashes, is very hard to understand and much more cumbersome.
More information can be found in the perldoc's perlre
The substitution regex (and other regex operators, like m///) can take any punctuation character as delimiter. This saves you the trouble of escaping meta characters inside the regex.
If you want to replace slashes, it would be awkward to write:
s/\/\//\//g;
Which is why you can write
s!//!/!g;
...instead. See http://perldoc.perl.org/perlop.html#Regexp-Quote-Like-Operators
And no, s/// is the substitution. m/// is the search, though I do believe the intended mnemonic is "match".
The exclamation marks are the delimiter; perl lets you choose any character you want, within reason. The statement is equivalent to the (much uglier) s/\/\//\//g — that is, it replaces // with /.