贪婪/懒惰(非贪婪)/占有量词如何在内部工作? [复制]
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
。无论如何,我认为这值得一提:)以上是关于贪婪/懒惰(非贪婪)/占有量词如何在内部工作? [复制]的主要内容,如果未能解决你的问题,请参考以下文章