正则表达式,分组和量词

5
我刚刚做了http://regexcrossword.com/上有趣的正则表达式填字游戏,发现我不理解量化组的含义,例如(.)+或(.)*。
让我试试http://ole.michelsen.dk/tools/regex.html,它提供了JavaScript和PHP正则表达式引擎:
要匹配的字符串是"Trololo!"(不带引号)。 (如果开启"全局匹配"会改变什么,它会作为JS的原始版本添加,因为在PHP模式下它没有改变任何内容。)
JS,  (.)+ => 0: Trololo! 1: ! 
JS', (.)+ => 0: Trololo! 
PHP, (.)+ => 0: Trololo! 0: ! 
JS,  (.)* => 0: Trololo! 1: ! 
JS', (.)* => 0: Trololo! 
PHP, (.)* => 0: Trololo! 1: 0: ! 1: 
JS,  (.){5} => 0: Trolo 1: o 
JS', (.){5} => 0: Trolo 
PHP, (.){5} => 0: Trolo 0: o 
JS,  (.){4} => 0: Trol 1: l 
JS', (.){4} => 0: Trol 1: olo! 
PHP, (.){4} => 0: Trol 1: olo! 0: l 1: ! 

这是否有一个规范答案来解释它的语义?


什么是 JSJS'?它们有什么区别? - Rohit Jain
1
我认为那个网站没有给你正确的组。请使用http://www.regexplanet.com/代替。 - Rohit Jain
1个回答

3
输出未正确标记。 首先,应该发生什么? 如果您重复一组,则每个新实例都会覆盖上一个捕获。 如果根本不使用该组,则会返回一个空字符串或在JS中类似于undefined的内容(这取决于风格)。 在regular-expressions.info上有一个关于此问题的好文章。
现在我们如何到达您的结果? 让我们从JavaScript开始。 所有标记为JS(非全局)的示例都符合上述说明。 它们在0中匹配所需字符的数量,并在1中捕获最后一个字符。 因此,我们可以忽略这些。
全局标记是什么? 这里输出被错误解释了。 当您在String.match()函数中使用全局标记时,您不再获取所有捕获的数组 - 而是仅获取所有匹配(每个匹配的组0)。 因此,在仅有一个匹配的+*{5}的情况下,您只会得到那一个结果。 对于目标字符串中有足够空间容纳两个匹配项的{4},因此生成的数组包含两个元素。 要使用全局标记获取所有捕获,您需要编写循环并改用RegExp.exec()(它一次给出一个匹配项,但是其所有捕获)。
还有PHP怎么办? 似乎它正在使用preg_match_all,无论如何都是全局的,这就是为什么使用g没有效果的原因。 +再次给出了您期望的结果。 {5}也是如此。
其他两个怎么样? 在这里,输出被错误地解释。 默认情况下,preg_match_all会给出一个二维数组,其中第一个索引对应于组,第二个索引对应于匹配。在您的输出中,它是另一种方式进行解释的。 因此,在存在多个匹配项时,第一对01是找到的两个匹配项的整个匹配项。 第二对01是您在这两个匹配项中捕获的内容。
因此,对于*,您首先以匹配项的形式获得完整字符串,然后以捕获的形式获取最后一个字符(标记为0的两件事),这是正确的。 然后,由于*允许零宽度匹配,因此您在字符串末尾获得另一个(空)匹配项,以及一个空捕获。 我不确定相应的JS'示例为什么不包含额外的空字符串,因为String.match将执行相同的操作。

对于 {4},你只会得到两个匹配项 (Trololo!),就像在 JavaScript 中使用捕获组 l! 一样,这完全没有问题。


首先,应该发生什么?确切地说,这就是问题所在 :-)实际上,我预期在abcd上匹配(.)*会得到0。abcd 1. a 2. b 3. c 4. d - 也就是说,我会得到更多的组,因为量词似乎对组进行了量化。但是,经过更长时间的思考,这似乎根本无法使用,因为组引用是固定的。 - Falko
1
@Falko,唯一支持此功能的正则表达式是.NET。在那里,您可以获得每个组的Group对象,其中包含一个Captures集合。 - Martin Ender
啊,很酷。但正如我所提到的,我无法想象这在实践中如何有所帮助。 - Falko
1
@Falko说你有类似...(13|52|78|33)...的东西,想要匹配所有数字,但可能会有任意数量。另一种方法是两步匹配,首先匹配序列,然后拆分它或其他操作。但在.NET中,您可以立即捕获所有这些数字。 .NET实际上更进一步,这些捕获保存在堆栈上,在匹配期间可以再次弹出元素,这允许在正则表达式中进行计数:请参见平衡组 - Martin Ender

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接