4

懒惰和贪婪的想法很容易理解,但我只*+在我的正则表达式(在 Java 中)[A]|[^B]*+(?!C)(A、B、C 是任意值)中看到/使用过一次,因为它在懒惰修饰符导致 StackOverflow 错误时起作用。

由于大多数搜索引擎无法搜索符号,我找不到任何关于此的文档。那么 *+ 究竟做了什么以及它是如何做到的呢?

4

3 回答 3

7

贪婪的量词匹配它可以匹配的所有内容,然后模式回溯,直到匹配成功。

一个惰性量词向前跟踪,直到匹配成功。

所有格量词匹配它可以匹配的所有内容并且从不回溯

The+表示所有格量词。If 可以用作,例如,++*+

这种防止回溯的能力意味着它可以阻止灾难性的回溯

于 2013-08-05T20:55:39.707 回答
2

正如其他答案指出的那样,*+是一个“占有量词”它尽可能多次匹配前一个元素,就像一个贪婪的量词一样,但从不回溯。

为什么这很有用?作为性能优化。此外,当正则表达式不匹配时作为性能优化。这是理解正则表达式的重要一点:当它们匹配时,它们的最坏情况总是发生。

根据使用的正则表达式引擎和正则表达式本身的细节,最坏情况下的性能有时可能会非常糟糕。举个简单的例子,使用这个正则表达式:a*a*a*b,匹配这个字符串:aaaaac

面对这种情况,一个标准的“NFA”类型的正则表达式引擎会做这样的事情:

  1. 尝试匹配第 1a次 5 次、第 2 次a零次和第 3 次a零次。
  2. 尝试b将 - 与c- 匹配失败。
  3. “回溯”并匹配第 1a次 4 次,第 2 次 1 次,第 3 次 0 次。
  4. 尝试再次匹配b- 它失败了。
  5. 再回溯,第1a次4次,第2次0次,第3次1次。
  6. ...
  7. 回溯,尝试第1a次3次,第2次2次,第3次零次……

(我认为您可以自己填写接下来的几百个步骤。)

如果正则表达式是a*+a*a*b,那将永远不会发生。它会更像:

  1. 尝试匹配第 1a次 5 次、第 2 次零次和第 3 次零次。
  2. 尝试匹配b-- 它失败了。
  3. 由于第一个a是“占有”,一旦匹配了5次,它就永远无法尝试匹配更少的次数。a并且由于字符串中没有s 可供其他a*s 匹配,因此它们只能匹配零次。没有什么可以尝试的了,所以整个比赛都失败了。
  4. 没有第 4 步。你完成了。当您的朋友正在等待他们的正则表达式完成执行时,您可以放松一下,打开您选择的冷饮。
于 2013-08-05T21:18:08.830 回答
1

X*+ 表示 X,零次或多次(占有)

所有格量词总是吃掉整个输入字符串,尝试一次(并且仅一次)匹配。与贪婪量词不同,所有格量词从不退缩,即使这样做会使整体匹配成功。

于 2013-08-05T20:56:20.447 回答