31

对于编写正则表达式的初学者来说,这似乎是一个巨大的困惑源,可能会导致隐藏的性能问题,而且典型的用例似乎是非贪婪的。

这仅仅是出于遗留原因(这是它最初是如何完成的,并且每个实现都复制它),还是有它的原因?

4

6 回答 6

11

歇斯底里的莱森斯


部分答案可能涉及实际计算中 RE 的起源。它们最初是自动机理论和形式语言理论的理论概念,直到Ken Thompson 自己编写了一个真正的实现并在qeded(1)中使用它们。

原始版本只有贪婪的语法,所以甚至没有做出决定。

于 2010-02-16T18:03:12.810 回答
9

在性能方面,由于回溯,惰性量词并不总是更快:http: //blog.stevenlevithan.com/archives/greedy-lazy-performance

至于实际设计,老实说,我不能说为什么量词默认是贪婪的,但我确实想知道使用什么控制字符来使量词变得贪婪而不是懒惰。我不认为?会削减它:-)

于 2010-02-16T17:54:41.060 回答
6

可能的原因:如果它不是贪婪的,正则表达式引擎需要回溯很多。

于 2010-02-16T17:53:31.397 回答
3

嗯,重要的是,计算机尽可能以可预测的方式运行。所以正确的行为应该遵循一个简单的规则,比如贪心匹配,这样至少有经验的程序员可以预测一段代码的结果。

至于一个典型的用例是否应该是非贪婪的,那么以下情况呢:假设我有一个包含 foo1909、bar3939、baz3331 等条目的文件,我只想提取这些数字。将 (\d*) 写为正则表达式似乎很自然。

你可能会说写 (\d*)\D 之类的一样容易,但基本上总是这样,程序员可以更明确,更少含糊。因为我们想要一个 100% 可预测的默认行为,并且在头脑中计算起来很简单,所以这对我来说似乎是合理的。

于 2010-02-16T17:54:27.207 回答
3

这里真正的问题是 Kleene 闭包运算符(星号);对于正则表达式中的其他所有内容,最长匹配与最短匹配相同。

当您从这些方面考虑时,您会意识到更现代的工具会意识到您两者都需要。我迟到了,所以我只能想到两个例子:

  • 两者都ksh提供大多数特殊变量更改运算符的bash“最长匹配”“最短匹配”形式。

  • Lua 正则表达式包括*Kleene 闭包最长匹配和-Kleene 闭包最短匹配。-当我忘记逃避文字符号时,这个总是咬我。

回到 Kleene 的原始工作,看看这是否会影响早期的最长匹配工具会很有趣。

于 2010-02-17T04:05:12.697 回答
1

一个典型的用例似乎是非贪婪的。

我想明确指出这是错误的,除非“典型用例”意味着 HTML 黑客。

一个简单的例子是编程语言的词法分析器。你根本不想要

foo = 42

被解释为 3 个变量,后跟等号,后跟 2 个数字。相反,通常您希望解析器考虑最长的匹配项。

在 HTML 出现之前,我们这些年长的人已经用贪婪的正则表达式生活了几十年,我们做得很好。即使在今天,我在 99% 的情况下都不会使用非贪婪的,诚然是因为我懒得查找语法,但也因为在很少的情况下你不能只写一个终止良好的贪婪。例如,要匹配一个字符串:

"(\\"|[^"])*"
于 2013-02-12T21:07:17.193 回答