简体   繁体   中英

Match and replace a word not in quotes (string contains escaped quotes)

How can I replace all occurrences of a particular word from a given string with another, provided the word does not occur within quotes. Note that the input string will most likely contain escaped quotes. The word itself will not contain any quotes.

[EDIT: The original wording was - "The input string will definitely contain escaped quotes". I realized later that it is not "definitely", but "most likely"].

Example: Replacing FOO by BAR

Input: FOO "FOO" 'FOO' " 1 + FOO + 2 " ABCFOOXYZ " str1\\"FOO\\"str3'FOO'\\'\\'" ' str1\\'FOOstr3"FOO"\\"\\"' \\"FOO\\"

Output: BAR "FOO" 'FOO' " 1 + FOO + 2 " ABCBARXYZ " str1\\"FOO\\"str3'FOO'\\'\\'" ' str1\\'FOOstr3"FOO"\\"\\"' \\"BAR\\"

Note that the last occurrence of FOO is not inside quotes, the quotes themselves have been escaped. Hence it gets replaced by BAR.

I am looking for a regexp in JavaScript.

clarification - The input string will contain single as well as double quotes, both possibly escaped. We should replace the word only when it is not quoted at all (neither with single nor with double quotes).

EDIT:

What I tried: I was able to get all occurrences of FOO which should NOT undergo a replacement (["'])(?:(?=(\\?))\\2.)*?\\1 The above will match all the quoted strings. They should be excluded from replacement.

I'm not a regexp pro and I cannot go beyond this, have tried a lot.

You could match everything between the single or double quotes by using a capture group, a character class and a back reference (['"]) so the same opening quote match the same closing quote. Then use an alternation to capture FOO in the second capturing group.

The method replace has a callback function where you can access the full match as the first parameter and the capture groups as the remaining parameters. Here you could test for the value of the second group. If it is FOO , then return BAR .

If it is not, return the full match.

(?:\s|^)(['"])(?:\1|.*?[^\\]\1)|(FOO)

Explanation

  • (?:\\s|^) Start of the string or a whitespace character
  • (['"]) Match ' or " in a capture group
  • (?: Non capturing group
    • \\1 Backreference to first capture group
    • | Or
    • .*?[^\\\\]\\1 Match any char except a newline non greedy followed by not a backslash and a backreference to group 1
  • ) Close non capturing group
  • | Or
  • (FOO) Capture group 2 containing FOO

Regex demo

 let pattern = /(?:\\s|^)(['"])(?:\\1|.*?[^\\\\]\\1)|(FOO)/g; let str = `FOO "FOO" 'FOO' " 1 + FOO + 2 " ABCFOOXYZ " str1\\\\"FOO\\\\"str3'FOO'\\\\'\\\\'" ' str1\\\\'FOOstr3"FOO"\\\\"\\\\"' \\\\"FOO\\\\"`; let res = str.replace(pattern, function(m, _, g2) { return g2 === "FOO" ? "BAR" : m; }); console.log(res); 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM