正则表达:谁更贪婪?

时间:2010-04-02 09:28:02

标签: java regex

我主要关心的是Java风格,但我也很欣赏有关其他人的信息。

假设你有一个这样的子模式:

(.*)(.*)

不是很有用,但是假设这两个捕获组(比如,\1\2)是更大模式的一部分,与这些组的反向引用相匹配等。

所以两者都是贪婪的,因为他们试图尽可能地捕捉,只在必要时少花钱。

我的问题是:谁更贪婪? \1是否具有优先权,只有在必须时才提供\2的份额?

怎么样:

(.*)(.*)(.*)

我们假设\1确实优先。让我们说它过于贪婪,然后吐出一个角色。谁先得到它?它总是\2还是\3

我们假设\2得到\1的拒绝。如果这仍然不起作用,谁现在吐出来? \2向[{1}}吐出,或\3先向\1吐出另一个吗?


奖金问题

如果你写这样的话会怎么样:

\2

现在(.*)(.*?)(.*) 不愿意。这是否意味着\2吐出\1,而\3只是不情愿地接受\2的拒绝?


实施例

对我来说,如果不提供具体的例子来展示我如何使用这些模式,也许这是错误的,但这里有一些:

\3

5 个答案:

答案 0 :(得分:15)

\1将具有优先权,\2\3将始终不匹配。然后\2优先于\3

作为一般规则这样想,反向跟踪将出现以满足匹配,它不会发生以满足贪婪,所以左边最好:)

回答跟踪和贪婪是我在这里要解决的问题,我建议friedl's Mastering Regular Expressions

答案 1 :(得分:8)

添加具体示例可以彻底改变问题的本质。它仍然像我在第一个答案中描述的那样开始,第一个(.*)吞噬所有角色,第二个和第三个组让它拥有它们,但是它必须匹配一个等号。

显然字符串末尾没有一个字符串,因此组#1逐个返回字符,直到正则表达式中的=与目标中的=匹配为止。然后正则表达式引擎开始尝试匹配(\1|\2|\3)+$并开始真正的乐趣。

组1放弃d,组2(仍为空)接受它,但正则表达式的其余部分仍然无法匹配。第1组放弃o和第2组匹配od,但正则表达式的其余部分仍然无法匹配。因此,随着第三组的参与,他们三人以各种可能的方式切换输入,直到实现整体匹配。据RegexBuddy报道,到达那里需要13426步。

在第一个例子中,贪婪(或缺乏贪婪)并不是真正的因素;唯一可以实现匹配的方法是,如果单词OhMyGod被捕获,则最终会发生这种情况。甚至哪个群体捕获哪个词都没有关系 - 就像我之前所说的那样,这是先到先得的。

在第二个和第三个例子中,只需要将前缀分成两个块:OhMyGod。第2组在第二个示例中捕获MyGod因为它是下一个并且它是贪婪的,就像在第一个示例中一样。在第三个例子中,每当第1组丢弃一个角色时,第2组(不情愿)让第3组取而代之,这样就是最后拥有MyGod的那个。

当然,它比那更复杂(和乏味),但我希望这能回答你的问题。我不得不说,这是你选择的一个有趣的目标字符串;如果一个正则表达式引擎有可能达到性高潮,我认为这些正则表达式将是它的关闭。 :d

答案 2 :(得分:2)

默认情况下,量词并不贪婪,他们只是仓促。在你的例子中,第一个(.*)将首先吞噬它所能做的一切,而不考虑整个正则表达式的需要。只有这样才能将控制权交给下一部分,如果有必要,它会回馈它刚刚采取的部分或全部内容(即回溯),以便正则表达式的其余部分可以完成其工作。

在这种情况下,这不是必需的,因为其他所有内容都可以合法地匹配零个字符。如果量词真的很贪婪,那么这三个群体就会讨价还价,直到他们尽可能均匀地划分输入;相反,第二组和第三组让第一组保持所需。如果它放在他们面前,他们会接受它,但他们不会为它而战。 (即使它们具有占有量量词,即(.*)(.*+)(.*+),也是如此。)

让第二个圆点明星不愿意改变任何东西,但是先切换 。一个不情愿的量词开始只通过匹配,然后交给下一部分。所以(.*?)(.*)(.*)中的第一组开始时没有匹配任何东西,然后第二组吞噬了所有东西,第三组在回家的路上喊“weee weee weee”。

这是的额外问题:如果你让所有三个量词都不情愿会怎么样? (提示:在Java中,这是一个API问题,因为它是一个正则表达式问题。)

答案 3 :(得分:0)

正则表达式按顺序工作,这意味着正则表达式只会在他找不到该组的解决方案时才会离开组,并最终进行一些回溯以使该字符串适合下一组。如果执行此正则表达式,您将在第一组中评估所有字符,在下一组中不评估(问号也无关紧要)。

答案 4 :(得分:0)

作为一个简单的一般规则:最左边的量词获胜。因此,只要以下量词识别出纯粹的可选子模式(无论它们是不成熟的),第一个都是全部。