为什么需要将sed中的正则表达式字符转义为正则表达式字符?


11

看来,例如
cat sed_data.txt | sed 's/\b[0-9]\{3\}\b/NUMBER/g'
,我必须转义字符以形成正则表达式。在这种情况下,我不得不使用花括号来进行多次解释。
为什么?我期望除非逃脱,否则一切都会是正则表达式字符。即相反。


有一篇关于在Vim中进行搜索的帖子,多少涵盖了这个问题,简称为“取决于命令的实现” ... unix.stackexchange.com/questions/90345/…–
Drav Sloan

@DravSloan:我不知道它是same.In Vim中你搜索的文本在默认情况下,你需要逃避这种情况下,格式搜索regex.But s/regex//g已经需要一个正则表达式,我会想到它是需要文本逃脱
吉姆(Jim)

Answers:


14

这是因为sed使用POSIX BRE(基本正则表达式)而不是您可能习惯于Perl或朋友使用的ERE(扩展正则表达式)。

sed(1)手册页:

REGULAR EXPRESSIONS
       POSIX.2 BREs should be supported, but they aren't completely because of
       performance problems.  The \n sequence in a regular expression  matches
       the newline character, and similarly for \a, \t, and other sequences.

以上链接的相关报价:

基本正则表达式或BRE风格对一种风格进行了标准化,该风格类似于传统UNIX grep命令所使用的一种。这几乎是当今仍在使用的最古老的正则表达式。使这种风味与众不同的一件事是,大多数元字符都需要反斜杠才能赋予其元字符自己的风味。包括POSIX ERE在内的大多数其他风味都使用反斜杠来抑制元字符的含义。

引用了克雷格·桑德斯的评论的逐字记录:

请注意,至少在GNU sed中,您可以通过-r或--regexp-extended命令行选项告诉sed使用扩展的正则表达式。如果您要避免过度转义来使sed脚本丑陋,这很有用。


1
请注意,至少在GNU sed中,您可以通过-r--regexp-extended命令行选项告诉sed使用扩展的正则表达式。如果您要避免过度转义来使sed脚本丑陋,这很有用。
cas 2013年

@CraigSanders谢谢你。已添加至答案。
Joseph R.

@CraigSanders,其他sed实现(当它们确实支持ERE,主要是BSD时)倾向于-E代替它使用(这更有意义,因为这与for相同grep。为什么GNU sed选择-r对我来说是个谜)。
斯特凡Chazelas

是的,对我来说也是个谜。使用-E会更有意义。然后添加-F,-G和-P以匹配GNU grep。IMO gawk也将从相同的RE args中受益,或者至少受益于-P。
cas

12

那是出于历史原因。

Regexp ed在70年代初期首次在Unix中通过实用程序引入。虽然ed是基于qed其实现由同一作者了解更复杂的正则表达式,ed只有理解^$[...].*\逃跑上述所有。

现在,当需要更多运营商时,必须找到一种在不破坏向后兼容性的情况下引入它们的方法。如果脚本用于将s ed命令s/foo() {/foo (var) {/g替换为foo() {with的所有实例,foo(var) { 并且您引入了(or {运算符,则该脚本将中断。

但是,没有脚本会这样做s/foo\(\) {/foo\(var\) {/,因为这与RE运算符相同,s/foo() {/foo(var) {/并且没有理由逃脱,(因为那不是RE运算符。因此,引入new \(\{operator不会破坏向后兼容性,因为使用较旧的语法不太可能破坏现有脚本。

就是这样。后来,\(...\)最初只为s ed命令添加了类似的功能s/foo\(.\)/\1bar/,后来又添加了grep '\(.\)\1'(但不允许添加\(xx\)*)。

在UnixV7(1979年,大约十年后)中,在新功能egrepawk实用程序中添加了一种新形式的正则表达式,称为扩展正则表达式(由于它们是新工具,因此不会破坏向后兼容性)。最后,它提供了Ken Thompson的古代版本qed(alternation运算符|,grouping (..)*)中可用的功能,并添加了一些运算符,例如+and ?(但不具有基本正则表达式的backref功能)。

后来BSD系统添加\<\>(既BRE和ERE),和SysV添加\{\}只BREs里面。

直到如此晚才被添加到ERE,并通过这种向后兼容{}被添加到ERE。并非所有人都添加了它。例如,除非强制进入POSIX一致性模式,否则awk不支持GNU 4.0.0(2011)版{

当GNU grep写于90年代初,这添加了所有来自BSD和SysV的东西(如\<{),并代替具有用于BRE和ERE两个单独的regexp语法和发动机,实现了相同的运营商两者,只的BRE同行(?{+必须用一个反斜杠(以与其他实施方式BRE兼容)。这就是为什么您可以.\+在GNU中进行操作grep(尽管它不是POSIX或不受其他实现支持),而您却可以(.)\1在GNU中进行egrep(尽管它不是POSIX或不受许多其他实现(包括GNU awk)支持)。

添加\x运算符不是以向后兼容的方式添加更多运算符的唯一方法。例如,perl使用了(?...)。仍然与ERE向后兼容,因为(?=...)在ERE中无效.*?vim对于类似的运营商,通过引入\@=.\{-}例如,做了不同的选择。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.