使用grep进行非贪婪匹配

9
据我所知,非贪婪匹配不是基本正则表达式(BRE)和扩展正则表达式(ERE)的一部分。然而,不同版本的grep(BSD和GNU)的行为似乎表明了相反的情况。
例如,让我们看下面的例子。我有一个字符串:
string="hello_my_dear_polo"

使用GNU grep

以下是从字符串中提取hello的几个尝试。

BRE尝试(失败)

$ grep -o "hel.*\?o" <<< "$string"
hello_my_dear_polo

输出产生了整个字符串,这表明非贪婪量词在BRE上不起作用。请注意,我仅转义了?,因为*不会失去其含义,也不需要转义。

ERE尝试(失败)

$ grep -oE "hel.*?o" <<< "$string"
hello_my_dear_polo

启用-E选项也会产生相同的输出,表明非贪婪匹配不是ERE的一部分。在这里我们使用ERE,因此不需要转义。

PCRE尝试(成功)

$ grep -oP "hel.*?o" <<< "$string"
hello

启用PCRE的-P选项表示非贪婪量词是其中的一部分,因此我们可以得到所需的hello输出。由于我们使用的是PCRE,因此不需要转义。

使用BSD grep:

以下是从字符串中提取hello的几次尝试。

BRE尝试(失败)

$ grep -o "hel.*\?o" <<< "$string"

使用BRE在BSD的grep命令中没有输出。

ERE尝试(成功)

$ grep -oE "hel.*?o" <<< "$string"
hello

在启用-E选项后,我很惊讶我能提取到我所需的输出。我的问题是关于我从这次尝试中得到的输出。PCRE尝试(失败):
$ grep -oP "hel.*?o" <<< "$string"
usage: grep [-abcDEFGHhIiJLlmnOoPqRSsUVvwxZ] [-A num] [-B num] [-C[num]]
    [-e pattern] [-f file] [--binary-files=value] [--color=when]
    [--context[=num]] [--directories=action] [--label] [--line-buffered]
    [--null] [pattern] [file ...]

使用 -P 选项给了我使用错误,这是预期的,因为 BSD 版本的 grep 不支持 PCRE。所以我的问题是,为什么在 BSD 版本的 grep 上使用 ERE,并使用非贪婪量词可以产生正确的输出,而在 GNU 版本的 grep 上却不行?这是一个bug,还是BSD版本的egrep未记录的特性,还是我对输出的误解?

1
对于这种情况,您可以使用 hel[^o]*o - Gumbo
1
感谢@Gumbo的评论。我同意,对于解决方案,人们会使用您建议的方法,但是我的问题是关于在BSD上打开-E选项时grep的奇怪行为。 - jaypal singh
1个回答

2
双量词是一种语法错误,可能会导致错误消息或未定义的行为。如果能收到错误消息则更好。
Perl对正则表达式的扩展比POSIX更新得多。在编写这些工具时,极少有人会尝试使用这种古怪的语法。贪婪匹配仅在20世纪90年代中期的Perl 5中引入。

感谢@tripleee。出现错误可能更有意义。但是,grep的两个变体都没有显示任何错误,也没有在手册页中记录任何内容。我正在运行grep(BSD grep)2.5.1-FreeBSD版本,手册页建议它最后更新于2010年7月28日这个页面似乎证实了BSD与GNU 100%兼容。 - jaypal singh
是的,但自2000年代初以来,相关标准并没有发生太大变化,当时Perl仍然是主要提供Perl正则表达式语法的语言。 - tripleee

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接