正则表达式:懒惰模式更糟糕吗?

12

我一直都是这样写正则表达式的

<A HREF="([^"]*)" TARGET="_blank">([^<]*)</A>

但是我刚刚学到了这个懒惰模式,并且我可以像这样编写它

<A HREF="(.*?)" TARGET="_blank">(.*?)</A>

使用第二种方法有什么不利之处吗?正则表达式肯定更加紧凑(即使SO更好地解析它)。

编辑:这里有两个最佳答案,它们指出了表达式之间的两个重要差异。 ysth的答案指出了非贪婪/懒惰表达式的一个弱点,其中超链接本身可能包括A标记的其他属性(绝对不好)。Rob Kennedy指出了贪婪表达式的一个弱点,即锚文本不能包括其他标记(绝对不好,因为它也无法获取所有锚文本)......因此,正则表达式是什么样子,看起来相同的懒惰和非懒惰解决方案可能不是语义上等价的。

编辑:Alan M关于表达式相对速度的第三个最佳答案。目前,我会将他的答案标记为最佳答案,这样人们就会给他更多积分 :)


当然可以,但显然一旦问题变老了,就没有人再关注它了。 - Dan Rosenstark
如果您可以更改被接受的答案,请随意这样做。我的回答实际上并没有回答问题,只是对其他答案进行了详细说明。 - Alan Moore
1
我不同意。有三个方面:匹配你不想要的东西、不匹配你想要的东西以及处理器需要多少工作量。没有人遇到超过一个问题。 - Dan Rosenstark
哦,我应该提到这比我在发布问题之前知道的多三个方面,所以这是一个巨大的帮助,感谢你们三个! - Dan Rosenstark
6个回答

12

另一个需要考虑的因素是目标文本的长度以及量化子表达式匹配了多少文本。例如,如果您试图在大型HTML文档中匹配整个<BODY>元素,您可能会尝试使用以下正则表达式:

/<BODY>.*?<\/BODY>/is

但这将会做很多不必要的工作,一个个地匹配字符并在每个字符之前有效地进行负向先行断言。你知道</BODY>标签将非常靠近文档的末尾,所以明智的做法是使用一般贪婪量词;让它吞掉整个剩余的文档,然后回溯几个字符来匹配结束标记。

在大多数情况下,你不会注意到贪婪和勉强量词之间的速度差异,但这是需要记住的事情。你在使用勉强量词时应该谨慎的主要原因是其他人指出的:他们可能会不情愿地这样做,但如果需要实现整体匹配,他们会匹配比你想要的更多的内容。


8

补充的字符类更加严格地定义了您想匹配的内容,因此只要可以,建议使用它。

非贪婪正则表达式将匹配您可能不想匹配的内容,例如:

<A HREF="foo" NAME="foo" TARGET="_blank">foo</A>

这里的“.*?”代表第一个匹配的内容

foo" NAME="foo

ysth: 我现在明白你的观点了,也就是说参数被重新排列了。 - Konrad Rudolph
很难说在那种情况下我想要匹配什么,因为它不是合法的HTML(或者至少对我来说没有意义)。 - Dan Rosenstark
1
Kenny:不,.*? 会先尝试匹配第一个双引号,但如果这不能成功匹配,它将继续到第二个双引号等。 - ysth
@Daniel Rosenstark,我正在修改示例以符合法律要求。 - ysth
啊,我和Konrad有一样的问题,感谢ysth的澄清。 - Kenny
显示剩余3条评论

7
请注意,您的示例不等同。您的第一个正则表达式将不会选择包含其他标签(如imgb)的链接。第二个正则表达式将会选择,我想这可能是您想要的。
除了意义上的差异外,我唯一能想到的缺点是非贪婪修饰符的支持并不像字符类否定那样普遍。在我检查之前,我认为它得到了更广泛的支持,但值得注意的是GNU Grep并未列入列表。如果您使用的正则表达式评估器支持它,请继续使用它。

嗨Rob,没错,我确实想要能够放在A标签之间的任何东西。无论我的正则表达式评估器是否支持它...哇,我甚至都不知道它不能支持。我得检查一下(我用的是AS3),然后我会编辑问题加上这个信息。 - Dan Rosenstark

3

这不是关于好与坏。我看到最常用的术语是贪婪和非贪婪,但无论如何它们都有两种不同的功能。您需要根据任务选择正确的选项。例如,在不想捕获一行中的多个匹配项时,请关闭贪婪选项。


1
“lazy”这个词在这里使用不太合适。您指的是非贪婪模式而不是贪婪模式。我不知道使用它是否有任何劣势。但在您的特殊情况下,也不应该高效。

感谢您的回答。这些人http://www.regular-expressions.info/repeat.html提到了懒惰或贪婪,我承认这比贪婪和非贪婪更没有意义。 - Dan Rosenstark
2
告诉你可能会感兴趣的是,“those guys”实际上是 Stack Overflow 成员 Jan Goyvaerts。;) - Alan Moore
是的,我真的不能抱怨SO成员的质量。我上次使用这种响应水平的技术论坛是xSLT论坛,一个名叫David Carlile(类似于这样)的著名大师亲自回答了大部分问题。 - Dan Rosenstark
Java将它们称为“reluctant”。量词有贪婪、占有和不情愿的。 - Scratte

1

非贪婪模式更好,不是吗?它向前工作,每次检查匹配并在找到一个时停止,而正常的 Kleene 闭包 (*) 向后匹配输入的其余部分并删除东西,直到找到匹配为止。

最终,它们做了不同的事情,但我认为非贪婪模式胜过贪婪模式。请记住,我还没有测试过这个,但现在我很好奇。


1
可能是实现相关的。感谢您的回答! - Dan Rosenstark

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