正则表达式仅捕获匹配中捕获组的最后一个实例

时间:2013-06-30 18:45:05

标签: javascript regex actionscript-3 ecmascript-5 capturing-group

我有两种不同语言的正则表达式,它们产生相同的奇数结果(javaScript和Flash)。我想知道的不是如何修复它,而是为什么会发生这种行为?

正则表达式:

\[(\\{2}|\\\]|[^\]])*\]

这里的目标是匹配一个括号中的字符串,并确保我不会停留在转义的括号中。

如果我有文本输入[abcdefg],则它正确匹配,但作为捕获组的一部分返回的唯一内容是g,我期望abcdefg。如果我将表达式更改为 \[((?:\\{2}|\\\]|[^\]])*)\],然后我得到了我想要的结果。

那为什么会这样呢?这会在其他语言中保持一致吗?

注意:将表达式简化为\[([^\]])*\]会产生同样的问题。

2 个答案:

答案 0 :(得分:7)

无论出现什么问题,ActionScript和JavaScript应该总是产生相同的结果,因为它们都实现ECMAScript(或其超集,但对于正则表达式,它们不应该不同意)。

但是,是的,这将以任何语言(或者说任何正则表达式)发生。原因是您正在重复捕获组。让我们举一个更简单的例子:匹配(.)*abc。所以我们重复的是(.)。第一次尝试时,引擎进入组,将a.匹配,离开组并捕获a。只有现在,量词才会启动并重复整个过程。所以我们再次进入该组,并匹配并捕获b。此捕获会覆盖前一个捕获,因此\1现在包含b。第三次重复再次相同:捕获将被c覆盖。

我不知道行为不同的正则表达式风格,并且唯一允许您访问所有先前捕获(而不是仅覆盖它们)的是.NET。

解决方案是p.s.w.g.建议。进行重复非捕获所需的分组(这将提高性能,因为您无需进行所有捕获和覆盖)并将整个事物包装在一个新组中。你的表达式有一个小缺陷:你需要在否定的字符类中包含反斜杠。否则,回溯可以在[abc\]中为您提供匹配。所以这里有一个表达式可以按预期工作:

\[((?:\\{2}|\\\]|[^\]\\])*)\]

Working demo.(不幸的是,它没有显示捕获,但它表明它在所有情况下都提供了正确的匹配)

请注意,您的表达式不允许其他转义序列。特别是单个\,后跟除]之外的任何内容都会导致您的模式失败。如果这不是你想要的,你可以使用:

\[((?:\\.|[^\]\\])*)\]

Working demo.

使用"unrolling-the-loop"技术可以进一步提高效果:

\[([^\]\\]*(?:\\.[^\]\\]*)*)\]

Working demo.

答案 1 :(得分:2)

尝试在捕获组中包含*量词,如下所示:

\[((?:\\{2}|\\\]|[^\]])*)\]