在re.search中重复使用编译的正则表达式

3
我发现以下代码:

我发现以下代码:

import re 

regex_compiled = re.compile('\d{2}-\d{3,5}')

res = re.search(regex_compiled, '12-9876')

我曾经认为re.search会尝试编译第一个参数,但实际上它已经被编译过了,所以应该会报错或在重复尝试编译之前调用regex_compiled.__repr__()regex_compiled.__str__()

为了确保,我将其与regex_compiled.search(...进行了比较:

>>> from timeit import timeit
>>> timeit("import re; regex_compiled = re.compile('\d{2}-\d{3,5}');     res = re.search(regex_compiled, '12-9876')")
1.3797054840251803

>>> timeit("import re; regex_compiled = re.compile('\d{2}-\d{3,5}');     res = regex_compiled.search('12-9876')")
0.7649686150252819
>>>

我很困惑为什么会有如此大的差异,因为在调试re.search时(在CPython v.2和v.3中),编译的模式被重复使用!希望有人能帮助解决这个问题。

执行环境:Ubuntu 16.04,64位


1
我不知道这是一个重复的问题。我完全了解缓存机制,这就是为什么我会在时间差异上遇到困难。那种差异让我感到不安。 - sophros
1个回答

2

re._compile 首先检查参数是否已缓存,然后再检查是否已编译。因此,当您将已编译的模式传递给 re.whatever 时,它会浪费一些时间计算和查找一个永远不会匹配的缓存键。重新编译模式和 OrderedDict 查找是重型操作,这似乎可以解释您观察到的差异。

这种行为的可能原因是,_compile 针对字符串模式进行了优化,这是它的主要用例,并旨在尽快返回缓存命中。

以下是一些计时:

from time import time
import re
import sys

print(sys.version)

pat = '\d{2}-\d{3,5}'
loops = 1000000

re.purge()

t = time()
for _ in range(loops):
    re._compile(pat, 0)
print('compile string  ', time() - t)

re.purge()

rc = re._compile(pat, 0)
t = time()
for _ in range(loops):
    re._compile(rc, 0)
print('compile compiled', time() - t)

结果:

$ python3 test.py
3.5.2 (default, Nov 23 2017, 16:37:01) [GCC 5.4.0 20160609]
compile string   0.5387749671936035
compile compiled 0.7378756999969482

$ python2 test.py
2.7.12 (default, Nov 20 2017, 18:23:56) [GCC 5.4.0 20160609]
('compile string  ', 0.5074479579925537)
('compile compiled', 1.3561439514160156)

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