我只是通过文档进行了固化分组和rubyinfo和一些简单的问题,我脑子里浮现如下:
- 为什么取名之际,“原子团”? 什么“原子”,它有通用分组没有。
- 如何原子团从一般的分组不同?
- 为什么原子团被称为非捕获组?
我想下面的代码,以理解,但有关于输出混乱,他们在相同的字符串是如何工作结果不同呢?
irb(main):001:0> /a(?>bc|b)c/ =~ "abbcdabcc"
=> 5
irb(main):004:0> $~
=> #<MatchData "abcc">
irb(main):005:0> /a(bc|b)c/ =~ "abcdabcc"
=> 0
irb(main):006:0> $~
=> #<MatchData "abc" 1:"b">
甲()
具有一定的性质(包括那些如(?!pattern)
, (?=pattern)
等,以及纯(pattern)
),但它们之间的共同属性分组 ,这使得任意的图案的单个单元(单位是我自己的术语),这是在重复有用的。
正常捕获(pattern)
具有捕获和组的属性。 拍摄机构,其在文本模式匹配内要捕获这样就可以用反向参考使用,以匹配或更换。 非捕获组(?:pattern)
没有捕获特性,所以它会节省一点空间,相比加快位(pattern)
,因为它不存储字符串的开始和结束索引图案内匹配。
原子团(?>pattern)
还具有非捕获特性,所以内部匹配的文本的位置不会被捕获。
原子团相比增加了捕捉或非捕获组的原子属性。 原子在这里是指:在当前位置,查找匹配模式固化分组中的第一个序列(首先是由发动机按照给定的模式匹配如何定义),并抓住它(所以回溯是不允许的)。
没有原子A组将允许回溯 - 它仍然会找到的第一个序列,然后如果匹配提前失败,它会走回头路,寻找下一个序列,直到有一个匹配整个正则表达式或发现所有的可能性都用尽。
例
输入字符串: bbabbbabbbbc
图案: /(?>.*)c/
通过第一场比赛.*
是bbabbbabbbbc
由于贪婪量词*
。 它会坚持到这场比赛,不允许c
从匹配。 匹配器将重试下一个位置到字符串的结束,同样的事情发生。 所以什么都没有正则表达式匹配。
输入字符串: bbabbbabbbbc
图案: /((?>.*)|b*)[ac]/
,测试/(((?>.*))|(b*))[ac]/
有3场比赛,这正则表达式,这是bba
, bbba
, bbbbc
。 如果使用正则表达式2号,这是相同的,但与捕获组增加了调试的目的,你可以看到,所有的比赛都匹配的结果b*
内。
你可以在这里看到回溯行为。
未经固化分组/(.*|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
随后的比赛将在这里继续。
“原子团”是一个在正则表达式将永远不会走回头路过去。 因此,在您第一个例子/a(?>bc|b)c/
如果bc
组中交替相匹配,那么它将永远不会走回头路了这一点,并尝试b
交替。 如果你稍微改变你的第一个例子来匹配"abcdabcc"
然后你会看到它仍然符合"abcc"
的字符串,而不是结束"abc"
的开始。 如果你不使用的原子团,那么它可以回溯过去的bc
并尝试b
交替,并最终匹配"abc"
的开始。
对于问题二,它是如何的不同,这只是一个你的第一个问题重新措辞。
最后,原子团不是“称为”非捕获组。 这不是他们的备用名称。 非捕获组不捕捉它们的内容组。 一般来说,当你对一个字符串匹配一个正则表达式,你可以检索所有匹配的群体,如果你使用的替换,可以替换使用反向引用像\1
插入捕获的组那里。 但是,非捕获组不提供此。 经典的非捕获组是(?:pattern)
。 的原子团,恰好也有非捕获性能,因此为什么它被称为非捕获组。
最近,我只好解释原子团给别人,我想我会调整并在这里分享的例子。
考虑the (big|small|biggest) (cat|dog|bird)
。
在大胆匹配
对于第一线,正则表达式引擎会发现the
。 然后,它会继续在我们的形容词( big
, small
, biggest
),发现big
。 具有匹配的“大”,前进和发现的空间。 然后,它着眼于我们的宠物( cat
, dog
, bird
),发现cat
,跳过它,并找到dog
。
对于第二行,我们的正则表达式会发现the
。 这将继续,并期待在big
,跳过它,看,发现small
。 然后它发现“”。 它着眼于“猫”,跳过它,着眼于“狗”,跳过它,并发现“鸟”。
对于第三行,我们的正则表达式会发现the
,它延续并找到big
相匹配的直接要求 ,并且前进。 它无法找到空间,所以它回溯 (倒带位置向它提出的最后的选择)。 它会跳过big
,看着small
,并跳过它。 它发现这也符合要求立即最大。 然后它发现“”。 它着眼于cat
,并跳过它,并匹配dog
。
对于第四行,我们的正则表达式会发现the
。 它将继续看big
,跳过它,看,发现small
。 然后它发现“”。 它着眼于和匹配cat
。
现在考虑the (?>big|small|biggest) (cat|dog|bird)
注意?>
上的形容词原子团。
在大胆匹配
对于第一线,第二线和四号线,我们的引擎的运行方式相同。
对于第三行,我们的正则表达式会发现the
,它延续并找到“大”,它匹配的即时需求 ,并继续。 它无法找到空间,但原子团,是最后的选择,为发动机,将不允许重新审查该选择(禁止回溯)。 由于它不能使一个新的选择,比赛有失败的,因为我们的简单表达式没有其他选择。
这仅仅是一个基本的总结。 发动机不会需要看整体cat
知道它不匹配dog
,只是看c是不够的。 当试图匹配鸟的c
在cat
和d
的狗都足以告诉引擎考虑其他的选择。
但是,如果你有... ((cat|snake)|dog|bird)
,发动机也会,当然,需要检查蛇之前下降到前一组和检查狗和鸟。
也有很多的选择,发动机不能没有打算过去似乎没有什么像比赛决定。 如果您有((red)?cat|dog|bird)
,该发动机将着眼于“R”,退了出去,请注意?
量词,忽略亚组(red)
,并寻找匹配。
文章来源: Confusion with Atomic Grouping - how it differs from the Grouping in regular expression of Ruby?