【问题标题】:Substitution pattern to escape quotes in vim替换模式以在vim中转义引号
【发布时间】:2014-02-07 16:01:18
【问题描述】:

我有一些文本在字符串中包含正确转义的双引号,而有些则没有 如下:

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

但我觉得我有点迷失了。

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

【问题讨论】:

    标签: regex vim escaping


    【解决方案1】:

    既然你说每行只有一个字符串,你可以链接替换命令来获得你想要的结果。 (这也导致命令的所有部分中的正则表达式更容易)

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

    解释:

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

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

      submatch(0) 是引号之间的所有内容。然后,我们将所有前面没有斜线的引号 (\\\@&lt;!") 替换为 \"

    :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
    

    【讨论】:

    • 您好,这个答案比 Jeff 的答案更好我已经修改了输入输出数据,以表明即使字符串中有多个引号它也可以工作。我会接受它。只有一个小情况它不会像我希望的那样工作 例如: bla\bla5 "aaa"bbb""BBB"ccc" bla5 become bla\bla5 "aaa\"bbb\""BBB\"ccc" bla5 情况是如果 "" 里面有两个双引号,也许你也知道如何使它适用于这种情况
    • 对不起,我按回车太早了,现在评论应该没问题
    • @szydan 我更改了第二个替换命令中的正则表达式,改为使用否定的外观。当有两个引号彼此相邻时,此方法有效。
    【解决方案2】:

    你可以在你已经编写的命令之一上粘贴一个逆全局。现在它只适用于不包含已转义引号的行:

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

    【讨论】:

    • 似乎有效。请您详细解释一下第一部分 v/\\/
    • 查看:h global。使用 v 而不是 g 将命令应用于与模式不匹配的行,在这种情况下只是反斜杠。
    • 感谢好技巧,但在这种情况下会失败 bla\bla3 "aaa"bbb"ccc" bla3 在实际字符串之前的 blabla 中有一个反斜杠
    【解决方案3】:
    :%s/\([^ \\]\)"\([^ ]\)/\1\\"\2/g
    

    这会查找前面没有斜杠或空格且后面没有空格的引号。

    【讨论】:

    • 凯文这没有用 - 我已经为问题添加了一个注释重要的部分是我只想转义一对双引号内的双引号,而不是所有双引号
    【解决方案4】:

    这可能有效:

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

    【讨论】:

    • 首先,你不需要捕获引号,你知道\2 永远是一个,其次,这也会得到外引号。
    猜你喜欢
    • 1970-01-01
    • 2019-05-23
    • 1970-01-01
    • 2017-08-05
    • 2011-05-11
    • 2015-07-31
    • 1970-01-01
    • 1970-01-01
    • 2011-06-09
    相关资源
    最近更新 更多