贪婪/懒惰(非贪婪)/占有量词如何在内部工作? [复制]

Posted

技术标签:

【中文标题】贪婪/懒惰(非贪婪)/占有量词如何在内部工作? [复制]【英文标题】:How do greedy / lazy (non-greedy) / possessive quantifiers work internally? [duplicate] 【发布时间】:2021-02-09 11:00:34 【问题描述】:

我注意到量词有 3 种不同类别:贪婪、懒惰(即非贪婪)和所有格。

我知道,粗略地说,greedy 量词试图通过首先读取整个输入字符串来获得最长的匹配,然后如果尝试继续失败,则一个一个地截断字符; lazy 量词尝试通过首先读取空字符串来获得最短匹配,然后如果尝试继续失败,则一个一个地添加字符; 占有量词尝试与贪婪量词相同的方式,但如果第一次尝试失败,它们将停止匹配。

但是,我不确定上述内容是如何在“内部”实施的,并希望得到澄清(希望有示例)。


例如,假设我们的输入字符串为"fooaaafoooobbbfoo"

如果正则表达式是"foo.*"(贪婪),那么正则表达式中的foo 是否会首先匹配输入字符串中的foo,然后.* 会读入aaafoooobbbfoo 作为“整个字符串”?或者.* 会首先将fooaaafoooobbbfoo 读入“整个字符串”,然后截断fooaaafoooobbbfoo 以尝试匹配正则表达式中的foo?如果是后者,fooaaafoooobbbfoo 会在每次尝试中从左侧截断还是从右侧截断?

如果我将"foo.*" 替换为".*foo""foo.*foo" 作为我的正则表达式,上述问题的答案会改变吗?如果我把那些贪婪的量词改成懒惰的和所有格的呢?

如果一个正则表达式中有多个量词,引擎将如何处理优先级(如果重要的话)?


提前致谢!

【问题讨论】:

提示:使用Regex Debugger实时查看步骤。 【参考方案1】:

对于您的输入字符串fooaaafoooobbbfoo

案例 1: 当您使用此正则表达式时:

foo.*

首先记住引擎从左到右遍历的事实。

考虑到上面的正则表达式将首先匹配输入开始处的foo,然后.*将贪婪匹配最长可能匹配foo之后的其余文本直到结束。此时匹配停止,因为在您的模式中 .* 之后没有可匹配的内容。

案例 2:当您使用此正则表达式时:

.*foo

这里.* 将在匹配最后一个foo 之前贪婪地匹配最长 可能的匹配,这正好是输入的末尾。

案例 3: 当您使用此正则表达式时:

foo.*foo

哪个将首先匹配输入中找到的foo,即foo,然后.*将在匹配最后一个foo之前贪婪地匹配最长可能的匹配,这是输入的结尾.

案例 4: 当您将此正则表达式与惰性量词一起使用时:

foo.*?foo

哪个将首先匹配输入中找到的foo,即在开始时foo,然后.*?将在匹配下一个foo之前延迟匹配最短可能匹配,这是@987654340的第二个实例@ 在输入中从位置 6 开始。

案例 5: 当您将此正则表达式与所有格量词一起使用时:

foo.*+foo

首先匹配输入中的foo,即在开始时foo,然后.*+ 使用占有量词,这意味着尽可能多地匹配,不返回。这将贪婪地匹配 longest 可能的匹配直到结束,并且由于所有格量词不允许引擎回溯,因此在部分末尾存在 foo 将导致失败,因为引擎将无法匹配最后一个 @987654347 @。

【讨论】:

非常感谢您的回答!我可以要求进一步澄清这个过程的细节:这是否意味着,比如"foo.*foo",正则表达式将首先在输入中找到第一次出现的foo(在开头),然后,@987654350 @ 将读入aaafoooobbbfoo,接下来,.* 将开始逐个截断aaafoooobbbfoo,直到截断的内容与正则表达式的最后一部分(即foo)匹配?如果是这样,请问这个截断究竟是如何进行的?它是从左到右还是从右到左截断aaafoooobbbfoo 截断或回溯是一次一个字符。因此引擎回溯一个位置并重新尝试匹配foo,并重复此过程,直到匹配成功或失败。在这种情况下,只要匹配最后一个 foo,匹配即成功。 那么我可以向您确认一下引擎是否从右到左回溯吗? (所以在这种情况下,aaafoooobbbfoo 变为aaafoooobbbfo 然后aaafoooobbbf 然后aaafoooobbb 然后匹配完成)谢谢你的耐心:) @J-A-S:是的,你是正确的。引擎一次向后移动 1 个位置,试图匹配位置 aaafoooobbbfoo, aaafoooobbbfo, aaafoooobbbf, aaafoooobbb 处的 foo。这是它成功匹配foo的时候。 我也尝试了正则表达式".*foo.*foo" 对输入,并且刚刚发现,在正则表达式中的第二个foo 第一次遇到时,在输入中引擎将移回索引在最后一个 foo 之前的一个字符,并从那里回溯正则表达式的第一个 foo。这允许正则表达式中的第二个foo 匹配输入中的最后一个foo。无论如何,我认为这值得一提:)

以上是关于贪婪/懒惰(非贪婪)/占有量词如何在内部工作? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

为啥惰性量词后跟问号会变得贪婪? [复制]

贪婪匹配和懒惰匹配

使用带有不情愿、贪婪和所有格量词的捕获组

全网最易懂的正则表达式教程(8 )- 贪婪模式和非贪婪模式

python-正则表达式

如何在 grep 中进行非贪婪匹配?