sed 全局替换在行尾应该如何表现?
How should sed global substitutions behave at end-of-line?
考虑 sed
程序 s/\(,\|$\)/-/g
。当 运行 在 GNU sed
下的各种输入上时,它给出了以下看起来有点不一致的交互:
- 空字符串 ->
-
,
-> -
a
-> a-
a,
-> a-
,a
-> -a-
表达式的$
部分是否匹配行尾似乎取决于最后一次匹配是否在行尾结束。我的直觉告诉我 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 可能是一个明智的选择。
考虑 sed
程序 s/\(,\|$\)/-/g
。当 运行 在 GNU sed
下的各种输入上时,它给出了以下看起来有点不一致的交互:
- 空字符串 ->
-
,
->-
a
->a-
a,
->a-
,a
->-a-
表达式的$
部分是否匹配行尾似乎取决于最后一次匹配是否在行尾结束。我的直觉告诉我 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 可能是一个明智的选择。