Substitution pattern to escape quotes in vim

escaping, regex, vim

Solution

Since you said there is only 1 string on each line, you can chain substitute commands to get the result that you want. (This also leads to easier regexes in all parts of the command)

:%s/"\zs.*\ze"/\=substitute(submatch(0), '\\\@<!"', '\\"', 'g')

Explanation:

- `:%s/"\zs.*\ze"` matches everything on the line between the first and the last quote. We use the greedy `.*` to do this. `\zs` marks the start of the match and `\ze` marks the end of the match.

After that we can pass the match to a second substitute command by adding `\=` to the start of the replacement. This means that the result of the expression after it will be the replacement string.

substitute(submatch(0), '\\\@<!"', '\\"', 'g')

`submatch(0)` is everything between the quotes. We then replace all quotes that don't have a slash before it (`\\\@<!"`) with a `\"`.

Take a loot at `:h sub-replace-expression`, `:h /\zs` and `:h /\ze`

Example Input:

bla1     "aaa"bbb"ccc"      bla1
bla2     "aaa\"bbb\"ccc"    bla2
bla\bla3 "aaa"bbb"ccc"      bla3 
blabla4  "aaa"bbb" "BBB"ccc" bla4       
bla\bla5 "aaa"bbb" "BBB"ccc" bla5
bla\bla5 "aaa"bbb""BBB"ccc" bla5

Example Output:

bla1     "aaa\"bbb\"ccc"      bla1
bla2     "aaa\"bbb\"ccc"    bla2
bla\bla3 "aaa\"bbb\"ccc"      bla3 
blabla4  "aaa\"bbb\" \"BBB\"ccc" bla4       
bla\bla5 "aaa\"bbb\" \"BBB\"ccc" bla5
bla\bla5 "aaa\"bbb\"\"BBB\"ccc" bla5

Problem

I have text with some lines contains properly escaped double quotes in strings and some not like below: ``` bla1 "aaa"bbb"ccc" bla1 bla2 "aaa\"bbb\"ccc" bla2 ``` The results after substitution should be ``` bla1 "aaa\"bbb\"ccc" bla1 bla2 "aaa\"bbb\"ccc" bla2 ``` but not: ``` bla1 "aaa\"bbb\"ccc" bla1 bla2 "aaa\\"bbb\\"ccc" bla2 ``` In other words it should escape the double quotes in lines where they are not escaped and do not touch lines which are already properly escaped So far I got the second result with this ``` %s:\(\s".\+\)\(".\+\)\(".\+"\s\):\1\\\2\\\3:g ``` Then I've tried a negative lookbehind to tell the engine to not match if there is a backslash before the quotes ``` (?<!\) which in vim should be something like @<!\ %s:\(\s".\+\)\@<!\\\(".\+\)@<!\\\(".\+"\s\):\1\\\2\\\3:g ``` But I think I've got a little lost. Note: There is only one such string per line The string is enclosed in double quotes and can contain double quotes inside - only this inside one should be escaped

Original source