混淆原子团 - 它从分组的区别在Ruby中的正则表达式?(Confusion with Atomic

2019-07-18 10:19发布

我只是通过文档进行了固化分组和rubyinfo和一些简单的问题,我脑子里浮现如下:

  1. 为什么取名之际,“原子团”? 什么“原子”,它有通用分组没有。
  2. 如何原子团一般分组不同?
  3. 为什么原子团被称为非捕获组?

我想下面的代码,以理解,但有关于输出混乱,他们在相同的字符串是如何工作结果不同呢?

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">

Answer 1:

()具有一定的性质(包括那些如(?!pattern)(?=pattern)等,以及纯(pattern) ),但它们之间的共同属性分组 ,这使得任意的图案的单个单元(单位是我自己的术语),这是在重复有用的。

正常捕获(pattern)具有捕获的属性。 拍摄机构,其在文本模式匹配内要捕获这样就可以用反向参考使用,以匹配或更换。 非捕获组(?:pattern)没有捕获特性,所以它会节省一点空间,相比加快位(pattern) ,因为它不存储字符串的开始和结束索引图案内匹配。

原子团(?>pattern)还具有非捕获特性,所以内部匹配的文本的位置不会被捕获。

原子团相比增加了捕捉或非捕获组的原子属性。 原子在这里是指:在当前位置,查找匹配模式固化分组中的第一个序列(首先是由发动机按照给定的模式匹配如何定义),并抓住它(所以回溯是不允许的)。

没有原子A组将允许回溯 - 它仍然会找到的第一个序列,然后如果匹配提前失败,它会走回头路,寻找下一个序列,直到有一个匹配整个正则表达式或发现所有的可能性都用尽。

输入字符串: bbabbbabbbbc
图案: /(?>.*)c/

通过第一场比赛.*bbabbbabbbbc由于贪婪量词* 。 它会坚持到这场比赛,不允许c从匹配。 匹配器将重试下一个位置到字符串的结束,同样的事情发生。 所以什么都没有正则表达式匹配。


输入字符串: bbabbbabbbbc
图案: /((?>.*)|b*)[ac]/ ,测试/(((?>.*))|(b*))[ac]/

有3场比赛,这正则表达式,这是bbabbbabbbbc 。 如果使用正则表达式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 

    随后的比赛将在这里继续。



Answer 2:

“原子团”是一个在正则表达式将永远不会走回头路过去。 因此,在您第一个例子/a(?>bc|b)c/如果bc组中交替相匹配,那么它将永远不会走回头路了这一点,并尝试b交替。 如果你稍微改变你的第一个例子来匹配"abcdabcc"然后你会看到它仍然符合"abcc"的字符串,而不是结束"abc"的开始。 如果你不使用的原子团,那么它可以回溯过去的bc并尝试b交替,并最终匹配"abc"的开始。

对于问题二,它是如何的不同,这只是一个你的第一个问题重新措辞。

最后,原子团不是“称为”非捕获组。 这不是他们的备用名称。 非捕获组不捕捉它们的内容组。 一般来说,当你对一个字符串匹配一个正则表达式,你可以检索所有匹配的群体,如果你使用的替换,可以替换使用反向引用像\1插入捕获的组那里。 但是,非捕获组不提供此。 经典的非捕获组是(?:pattern) 。 的原子团,恰好也有非捕获性能,因此为什么它被称为非捕获组。



Answer 3:

最近,我只好解释原子团给别人,我想我会调整并在这里分享的例子。

考虑the (big|small|biggest) (cat|dog|bird)

在大胆匹配

  • 大狗
  • 小鸟
  • 最大的狗
  • 猫小

对于第一线,正则表达式引擎会发现the 。 然后,它会继续在我们的形容词( bigsmallbiggest ),发现big 。 具有匹配的“大”,前进和发现的空间。 然后,它着眼于我们的宠物( catdogbird ),发现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是不够的。 当试图匹配鸟的ccatd的狗都足以告诉引擎考虑其他的选择。

但是,如果你有... ((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?