【问题标题】:How do I write a SED regex to extract a string delimited by another string?如何编写 SED 正则表达式来提取由另一个字符串分隔的字符串?
【发布时间】:2013-02-19 19:58:57
【问题描述】:

我正在使用 GNU sed 版本 4.2.1,并且我正在尝试编写一个非贪婪的 SED 正则表达式来提取一个由其他两个字符串分隔的字符串。当分隔字符串是单字符时,这很容易:

s:{\([^}]*\)}:\1:g

在该示例中,字符串由左侧的“{”和右侧的“}”分隔。

如果分隔字符串是多个字符,比如 '{{{' 和 '}}}' 我可以像这样调整上面的表达式:

s:{{{\([^}}}]*\)}}}:\1:g

所以中心表达式匹配任何不包含 '}}}' 结束字符串的内容。但这仅在匹配字符串根本不包含 '}' 时才有效。比如:

{{{cannot match {this broken} example}}}

不会起作用,但是

{{{can match this example}}}

确实有效。当然

s:{{{\(.*\)}}}:\1:g

总是有效,但很贪心,因此不适合在同一行出现多个模式的情况。

我理解 [^a] 表示除 a[^ab] 之外的任何内容排除 3 个连续字符的序列。

那么我如何为 SED 编写一个正则表达式来匹配一个由其他两个字符串分隔的字符串?

【问题讨论】:

    标签: regex sed


    【解决方案1】:

    使用sed,您可以执行以下操作:

    sed -e :a -e 's/\(.*\){{{\(.*\)}}}/\1\2/ ; ta'
    

    与:

    {{{can match this example}}} {{{can match this 2nd example}}}
    

    这给出了:

    can match this example can match this 2nd example
    

    不是惰性匹配,而是从右到左替换,可以利用sed的贪心。

    【讨论】:

      【解决方案2】:

      [^}}}] 不起作用是正确的。否定字符类匹配不是其中一个字符的任何内容。重复字符不会改变逻辑。所以你写的和[^}]一样。 (当表达式中没有大括号时,很容易理解为什么会这样)。

      在 Perl 和兼容的正则表达式中,您可以使用 ? 使 *+ 不贪婪:

       s:{{{(.*?)}}}:$1:g
      

      这将始终匹配开头 {{{ 之后的第一个 }}}

      但是,this is not possible in Sed。事实上,我不认为 Sed 有任何方法可以进行这种匹配。唯一的另一种方法是使用 Sed 也没有的高级功能,例如前瞻。

      您可以通过-pe 选项轻松地以类似 sed 的方式使用 Perl,这会导致它从命令行 (-e) 获取一行代码并自动循环遍历每一行并打印结果(-p)。

      perl -pe 's:{{{(.*?)}}}:$1:g'
      

      用于就地编辑文件的-i 选项也很有用,但请先确保您的正则表达式正确!

      欲了解更多信息,请参阅perlrun

      【讨论】:

      • 感谢您的回答 - 这是我所怀疑的,因为我知道 sed 无法向前看。我发现在你的例子中我不需要转义捕获组:'s:{{{(.*?)}}}:$1<:g'(事实上,当我这样做时,它没有工作)。
      • @starfry,哎呀,你是对的捕获组。那是一个错字。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-07-19
      • 2019-07-02
      • 1970-01-01
      • 2014-08-17
      相关资源
      最近更新 更多