非捕获组是否冗余



可选的非捕获组是多余的吗?

是以下正则表达式:

(?:wo)?men

在语义上是否等同于下面的正则表达式?

(wo)?men

您的(?:wo)?men(wo)?men在语义上是等价的,但在技术上是不同的,即,第一个使用非捕获组,另一个使用捕获组。因此,问题是当我们有捕获组时,为什么要使用非捕获组?

非捕获组有时是有帮助的。

  1. 为了避免过多的反向引用(记住有时很难使用大于9的反向引用)
  2. 为了避免99个编号的反向引用限制的问题(通过减少编号的捕获组的数量)(来源: regular - expressionsinfo : 大多数正则表达式支持多达99个捕获组和两位数的反向引用。)
    注意这不适用于Java正则表达式引擎,也不适用于PHP或。net正则表达式引擎。
  3. 减少在堆栈中存储捕获所造成的开销
  4. 我们可以添加更多的分组到现有的正则表达式,而不会破坏捕获组的顺序。

同时,它使我们的匹配更简洁:

您可以使用非捕获组来保留组织或组的好处,但没有捕获的开销。

重构现有正则表达式以将捕获组转换为非捕获组似乎不是一个好主意,因为它可能会破坏代码或需要太多的努力。

其他地方也有同样的问题,我用Python的一个例子给出了答案:

它没有相同的效果。-在一种情况下,组被捕获并可访问,在另一种情况下,它只用于完成匹配。

当人们对访问组的值不感兴趣时,他们使用非捕获组-为有许多匹配的情况节省空间,但在正则表达式引擎为此进行优化的情况下,也可以获得更好的性能。

一个无用的Python示例来说明这一点:

from timeit import timeit
import re
chars = 'abcdefghij'
s = ''.join(chars[i % len(chars)] for i in range(100000))

def capturing():
    re.findall('(a(b(c(d(e(f(g(h(i(j))))))))))', s)

def noncapturing():
    re.findall('(?:a(?:b(?:c(?:d(?:e(?:f(?:g(?:h(?:i(j))))))))))', s)

print(timeit(capturing, number=1000))
print(timeit(noncapturing, number=1000))
输出:

5.8383678999998665
1.0528525999998237

注意:这是无视PyCharm(如果你碰巧使用它)警告"不必要的非捕获组"——这个警告是正确的,但显然不是全部真相。这在逻辑上是不需要的,但绝对没有同样的实际效果。

如果你想摆脱它们的原因是为了抑制这样的警告,PyCharm允许你这样做:

# noinspection RegExpUnnecessaryNonCapturingGroup
re.findall('(?:a(?:b(?:c(?:d(?:e(?:f(?:g(?:h(?:i(j))))))))))', s)

另一个迂腐的注意事项:上面的例子也不是严格意义上的逻辑等价。但是它们匹配相同的字符串,只是结果不同。

c = re.findall('(a(b(c(d(e(f(g(h(i(j))))))))))', s)
nc = re.findall('(?:a(?:b(?:c(?:d(?:e(?:f(?:g(?:h(?:i(j))))))))))', s)

c是一个10元组列表([('abcdefghij', 'bcdefghij', ..), ..]),而nc是一个单字符串列表(['j', ..])。

最新更新