替换模式以逃避vim中的引号

时间:2014-02-07 16:01:19

标签: regex vim escaping

我有一些文字,其中一些行包含字符串中正确转义的双引号,而某些行则不包含 如下所示:

bla1 "aaa"bbb"ccc" bla1
bla2 "aaa\"bbb\"ccc" bla2

替换后的结果应为

bla1 "aaa\"bbb\"ccc" bla1
bla2 "aaa\"bbb\"ccc" bla2

但不是:

bla1 "aaa\"bbb\"ccc" bla1
bla2 "aaa\\"bbb\\"ccc" bla2

换句话说,它应该在没有转义的行中转义双引号 并且不要触摸已经正确转义的行

到目前为止,我用这个

获得了第二个结果
%s:\(\s".\+\)\(".\+\)\(".\+"\s\):\1\\\2\\\3:g

然后我尝试了一个负面的观察,告诉引擎不匹配 如果在引号

之前有反斜杠
(?<!\) which in vim should be something like @<!\

%s:\(\s".\+\)\@<!\\\(".\+\)@<!\\\(".\+"\s\):\1\\\2\\\3:g

但我觉得我有点失落。

注意:
每行只有一个这样的字符串 该字符串用双引号括起来,里面可以包含双引号 - 只有一个内部应该被转义

4 个答案:

答案 0 :(得分:3)

由于您说每行只有一个字符串,您可以链接替换命令以获得所需的结果。 (这也可以使命令的所有部分更容易正则表达式)

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

说明:

  1. :%s/"\zs.*\ze"匹配第一个和最后一个引号之间的所有内容。我们使用贪婪的.*来做到这一点。 \zs标记了比赛的开始,\ze标志着比赛的结束。
  2. 之后我们可以通过将\=添加到替换的开头来将匹配传递给第二个替换命令。这意味着它之后的表达式的结果将是替换字符串。

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

    submatch(0)是引号之间的所有内容。然后,我们将所有没有斜杠的引号(\\\@<!")替换为\"

  3. :h sub-replace-expression:h /\zs:h /\ze

    处获取战利品

    示例输入:

    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
    

    示例输出:

    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
    

答案 1 :(得分:1)

你可以在你已经写过的命令之一上加上反向全局。现在它只适用于不包含已转义的引号的行:

:v/\\"/s:\(\s".\+\)\(".\+\)\(".\+"\s\):\1\\\2\\\3:g

答案 2 :(得分:0)

:%s/\([^ \\]\)"\([^ ]\)/\1\\"\2/g

这会发现引号前面没有斜杠或空格,后面没有空格。

答案 3 :(得分:0)

这可能有效:

%s/\([^\\]\)\("\)/\1\\\2/g