【问题标题】:Sed: backreference substring from line matching regexp in 's' commandSed:来自's'命令中的行匹配正则表达式的反向引用子字符串
【发布时间】:2014-04-16 18:59:16
【问题描述】:

我正在尝试使用 sed,最近我发现了一些有趣的行为。但是,我找不到任何描述它的文档。

假设我们有一个名为“sedtest”的文件:

$cat sedtest
 hello 0 world
 example
 4 sed
 Phone number: 123-456-789

接下来,我将通过 sed 运行它:

$cat sedtest | sed '/\([[:digit:]]\+\)/s,,(\1),'
 hello (0) world
 example
 (4) sed
 Phone number: (123)-456-789

这是相当容易理解的 sed 脚本:

  1. 首先,它通过正则表达式\([[:digit:]]\+\)匹配字符串,这意味着“匹配包含1个或多个数字的字符串”。请注意,我在这里还使用s-command-style \(\) 括号来标记子字符串(是否允许?)。
  2. 如果匹配,它会继续使用s 命令s,,(\1),(带有空的正则表达式字段),这意味着“将匹配的子字符串替换为(\1)”。

最初我认为它应该会因错误而失败,因为\1 和类似的反向引用应该只适用于来自s 命令匹配器字段的子字符串,在这种情况下它是空的。

但结果就像是s,\([[:digit:]]\+\),(\1), 脚本(\regexp\ 匹配器移入s 命令匹配器字段)!

所以,问题是:从s//replace/ 命令反向引用由\regexp\ 规则匹配的文本子串是否正常(即,它是期望的行为),就像它们被s/regexp/replace/ 命令匹配一样?

附言

我的 sed 版本是:GNU sed 4.2.1

问题背后的动机是你可以这样做:

sed '/^Number: \([[:digit:]]\+\)$/{s,,#NUMBER: (\1),;p;d};q 1',即

  1. /^Number: \([[:digit:]]\+\)$/ - 匹配Number: 12345 的每一个字符串,如果匹配:
    • s,,#NUMBER: (\1), - 将其替换为 #NUMBER: (12345)
    • p - 打印出来
    • d - 清除模式空间,开始新循环(获取新行并从头开始解析脚本表达式)
  2. q 1 - 使用代码 1 退出。此命令仅在步骤 1 中未发生匹配时执行(因为 d 命令存在) - 它检查“不匹配”的情况,在我的情况下意味着“不允许的字符串”并且必须导致错误。

这里的主要技巧是在替换发生后执行pd 命令,这在使用“普通”s/match/replace/ 命令时是不可能的。

【问题讨论】:

    标签: sed


    【解决方案1】:

    这很正常。除非您进行另一场比赛,否则不会清除反向引用保留空间。由于s 的正则表达式为空,\1 指的是之前的捕获组。你可以看到区别:

    $ sed '/\([[:digit:]]\+\)/s,\(a\),(\1),' sedtest
    hello 0 world
     example
     4 sed
     Phone number: 123-456-789
    

    没有匹配项(带有数字的行也有a,但反向引用保持已被清除

    $sed '/\([[:digit:]]\+\)/s,\(e\),(\1),'
    h(e)llo 0 world
     example
     4 s(e)d
     Phon(e) number: 123-456-789
    

    e 匹配并成为反向引用。

    如果您不希望这种行为,则不应首先通过将\( \) 放在[[:digit:]] 周围来创建反向引用。

    【讨论】:

      猜你喜欢
      • 2020-11-14
      • 2020-07-14
      • 1970-01-01
      • 2011-09-09
      • 2012-03-31
      • 2011-11-08
      • 2013-01-23
      • 2022-07-11
      • 1970-01-01
      相关资源
      最近更新 更多