A ()
具有一些属性(包括诸如(?!pattern)
, (?=pattern)
等以及平原(pattern)
),但它们之间的共同属性是grouping,这使得任意模式成为一个单元(单元是我自己的术语),这在重复中很有用。
正常捕获(pattern)
具有以下属性捕获 and group。捕获意味着与内部模式匹配的文本将被捕获,以便您可以在匹配或替换时将其与反向引用一起使用。非捕获组(?:pattern)
没有 capture 属性,因此与(pattern)
因为它不存储与内部模式匹配的字符串的开始和结束索引。
原子分组(?>pattern)
还具有非捕获属性,因此内部匹配的文本位置不会被捕获。
原子分组增加了以下属性atomic与捕获组或非捕获组相比。这里原子的意思是:在当前位置,找到first序列(首先是由引擎如何根据给定的模式匹配来定义的)与原子分组内的模式匹配并保留它(因此不允许回溯)。
没有原子性的组将允许回溯 - 它仍然会找到第一个序列,然后如果前面的匹配失败,它将回溯并找到下一个序列,直到找到整个正则表达式的匹配或用尽所有可能性。
Example
输入字符串:bbabbbabbbbc
图案:/(?>.*)c/
第一场比赛由.*
is bbabbbabbbbc
由于贪婪量词*
。它将保留这场比赛,不允许c
来自匹配。匹配器将在字符串末尾的下一个位置重试,并且会发生相同的情况。所以根本没有任何东西与正则表达式匹配。
输入字符串:bbabbbabbbbc
图案:/((?>.*)|b*)[ac]/
, 供测试用/(((?>.*))|(b*))[ac]/
该正则表达式有 3 个匹配项,分别是bba
, bbba
, bbbbc
。如果您使用第二个正则表达式,它是相同的,但添加了用于调试目的的捕获组,您可以看到所有匹配都是匹配的结果b*
inside.
您可以在此处查看回溯行为。
-
没有原子分组/(.*|b*)[ac]/
,由于最后回溯匹配,该字符串将有一个匹配,即整个字符串[ac]
。请注意,引擎将返回到.*
回溯 1 个字符,因为它还有其他可能性。
Pattern: /(.*|b*)[ac]/
bbabbbabbbbc
^ -- Start matching. Look at first item in alternation: .*
bbabbbabbbbc
^ -- First match of .*, due to greedy quantifier
bbabbbabbbbc
X -- [ac] cannot match
-- Backtrack to ()
bbabbbabbbbc
^ -- Continue explore other possibility with .*
-- Step back 1 character
bbabbbabbbbc
^ -- [ac] matches, end of regex, a match is found
-
通过原子分组,所有可能性.*
被切断并仅限于第一场比赛。因此,在贪婪地吃掉整个字符串并且无法匹配之后,引擎必须去寻找b*
模式,成功找到与正则表达式的匹配项。
Pattern: /((?>.*)|b*)[ac]/
bbabbbabbbbc
^ -- Start matching. Look at first item in alternation: (?>.*)
bbabbbabbbbc
^ -- First match of .*, due to greedy quantifier
-- The atomic grouping will disallow .* to be backtracked and rematched
bbabbbabbbbc
X -- [ac] cannot match
-- Backtrack to ()
-- (?>.*) is atomic, check the next possibility by alternation: b*
bbabbbabbbbc
^ -- Starting to rematch with b*
bbabbbabbbbc
^ -- First match with b*, due to greedy quantifier
bbabbbabbbbc
^ -- [ac] matches, end of regex, a match is found
接下来的比赛将从这里继续进行。