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

IT技术 javascript regex actionscript-3 ecmascript-5 capturing-group
2021-03-07 08:35:11

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

正则表达式:

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

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

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

那么为什么会发生这种情况呢?这在其他语言中会保持一致吗?

注意:简化表达式以\[([^\]])*\]产生相同的问题。

2个回答

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

但是,是的,这将发生在任何语言(或者更确切地说是任何正则表达式风格)中。原因是您正在重复捕获组。让我们来简单的例子:比赛(.)*反对abc所以我们要重复的是(.)它第一次试图,发动机进组,火柴a.,离开团的捕捉a只有现在量词才起作用并重复整个过程。所以我们再次进入该组,并匹配和捕获b此捕获覆盖了前一个捕获,因此\1现在包含b. 第三次重复同样如此:捕获将被覆盖c

我不知道有什么表现不同的正则表达式风格,唯一可以让您访问所有以前的捕获(而不是仅仅覆盖它们)的是 .NET。

解决方案是 pswg 提出的一种解决方案。将重复所需的分组设为非捕获(这将提高性能,因为无论如何您都不需要所有捕获和覆盖)并将整个内容包装在一个新组中。不过,您的表达式有一个小缺陷:您需要在否定字符类中包含反斜杠。否则,回溯可能会在[abc\]. 因此,这里有一个可以按您预期工作的表达式:

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

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

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

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

工作演示。

使用“展开循环”技术可以进一步提高性能

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

工作演示。

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

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