sed 全局替换在行尾应该如何表现?

How should sed global substitutions behave at end-of-line?

考虑 sed 程序 s/\(,\|$\)/-/g。当 运行 在 GNU sed 下的各种输入上时,它给出了以下看起来有点不一致的交互:

表达式的$部分是否匹配行尾似乎取决于最后一次匹配是否在行尾结束。我的直觉告诉我 g 标志应该从最后一次替换的末尾重复匹配,直到正则表达式匹配失败,在这种情况下,这个程序应该总是附加一个额外的 - 到行;但当然,我的直觉不一定符合 POSIX 规范。

阅读 sed 的 POSIX 联机帮助页,它对 s 命令的 g 标志说明如下:

Globally substitute for all non-overlapping instances of the BRE rather than just the first one. If both g and n are specified, the results are unspecified.

输入 "overlaps" 中的最后一个 , 是否带有 EOL 似乎有待解释。还有什么可以澄清这一点吗?此行为符合规范,还是 GNU sed 中的错误?

如评论中所述,然后在 chat

中进行了更广泛的讨论

您使用的表示法(具体来说,\| 表示交替)未由 POSIX sed 指定,因此尚不清楚关于 POSIX 的要求,有很多话要说。它说,部分:

The sed utility shall support the BREs described in XBD Basic Regular Expressions.

反过来说:

The interpretation of an ordinary character preceded by a <backslash> ('\') is undefined, except for:
• The characters ')', '(', '{', and '}'
• The digits 1 to 9 inclusive (see BREs Matching Multiple Characters)
• A character inside a bracket expression.

这主要意味着您不能向 POSIX 请求所需的行为。我认为备选方案是从左到右评估的,但是 $ 上下文出现在逗号之后。我简要浏览了您的列表,没有看到令人惊讶的行为。在线上的第一场比赛总是赢,不是吗?

我不确定它到底是如何工作的,但我猜想换行符从行中删除,然后在 EOL 之前的字符上完成替换,并且扫描恢复但处于 EOL,所以它什么都不做。

POSIX sed 可能会根据 POSIX regexec() 等函数来实现。您指出 g-修饰符的解释留给 sed。我怀疑它的行为可能或多或少与我假设的一样。

在聊天中,我们还注意到:

  • GNU sed -r 用于使用扩展的正则表达式,但它们的行为似乎相似(当符号相应更改时)。

  • BSD 和 Mac OS X sed-E 用于使用扩展正则表达式。

  • Busybox sed 似乎工作类似,因此该行为似乎在 sed.

    的多个实现中很常见
  • 使用 Mac OS X,我们得到了意想不到的行为:

      $ echo ",a" | sed -E 's/(,|$)/-/g'
      -
      $
    

    在没有更好的假设的情况下,我们将其指定为'inexplicable'或'possibly (probably?) buggy'。 a 没有明显的原因丢失。

  • 使用 Perl 或 Python 可能是一个明智的选择。