Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Substitution pattern to escape quotes in vim

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

like image 260
szydan Avatar asked Feb 10 '26 19:02

szydan


1 Answers

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:

  1. :%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.
  2. 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
like image 152
FDinoff Avatar answered Feb 13 '26 10:02

FDinoff