为什么在Python中捕获组时正则表达式搜索速度较慢?

Dhr*_*hak 18 python regex

我有一个应用程序代码,可以从配置中动态生成正则表达式以进行一些解析.当两个变化的定时性能时,正被捕获的OR正则表达式的每个部分的正则表达式变化明显慢于正常正则表达式.原因是regex模块内部某些操作的开销.

>>> import timeit
>>> setup = '''
... import re
... '''   

#no capture group 
>>> print(timeit.timeit("re.search(r'hello|bye|ola|cheers','some say hello,some say bye, or ola or cheers!')", setup=setup))
0.922958850861

#with capture group
>>> print(timeit.timeit("re.search(r'(hello)|(bye)|(ola)|(cheers)','some say hello,some say bye, or ola or cheers!')", setup=setup))
1.44321084023

#no capture group
>>> print(timeit.timeit("re.search(r'hello|bye|ola|cheers','some say hello,some say bye, or ola or cheers!')", setup=setup))
0.913202047348

# capture group
>>> print(timeit.timeit("re.search(r'(hello)|(bye)|(ola)|(cheers)','some say hello,some say bye, or ola or cheers!')", setup=setup))
1.41544604301
Run Code Online (Sandbox Code Playgroud)

问题:使用捕获组时,导致性能大幅下降的原因是什么?

Fed*_*zza 19

原因很简单,使用捕获组指示Engine将内容保存在内存中,而使用非捕获组则表示引擎不保存任何内容.请考虑您告诉引擎执行更多操作.

例如,使用此正则表达式(hello|bye|ola|cheers)(hello)|(bye)|(ola)|(cheers)将比使用原子组或非捕获原子组的影响大得多(?:hello|bye|ola|cheers).

使用正则表达式时,您知道是否要捕获或不捕获内容,如上所述.如果你想捕获任何这些单词,你将失去性能,但如果你不需要捕获内容,那么你可以通过改进它来保存性能,就像使用非捕获组一样

我知道你标记了python,但是已经准备好了javascript的在线基准测试,以显示捕获和非捕获组如何影响js正则表达式引擎.

https://jsperf.com/capturing-groups-vs-non-capturing-groups

在此输入图像描述

  • @RadLexus,我同意.在JS正则表达式,使用捕获组和非捕获组的影响在20%左右(这是一个在很大程度上影响恕我直言),但对Python的似乎是40%左右,所以如你所说的内存/对象管理可能的罪魁祸首剩下20%. (2认同)

Wik*_*żew 11

您的模式仅在捕获组中有所不同.在正则表达式模式中定义捕获组并使用模式时re.search,结果将是一个 MatchObject实例.每个匹配对象将包含与模式中的捕获组一样多的,即使它们是空的.这是re内部的开销:添加(列表)组(内存分配等).请注意,组还包含诸如匹配的文本的起始和结束索引等详细信息(请参阅MatchObject参考资料).

  • 我不认为使用*冗余*非捕获组(如您在此处使用的)最终会产生更好的性能.我记得相反的结果(在PHP中使用PCRE).关键是捕获组越多,模式的效率越低,因此规则是摆脱任何*冗余捕获组*.其余的已经是纳米优化,您可以跳过.请注意,大多数用户认为非捕获组的可读性较差. (4认同)