我的问题是关于解析日志文件并删除每一行的可变部分以便对它们进行分组。例如:
s = re.sub(r'(?i)User [_0-9A-z]+ is ', r"User .. is ", s)
s = re.sub(r'(?i)Message rejected because : (.*?) \(.+\)', r'Message rejected because : \1 (...)', s)
我有大约 120 多个像上面这样的匹配规则。
在连续搜索 100 个不同的正则表达式时,我没有发现任何性能问题。但是当应用 101 个正则表达式时会出现巨大的减速。
将我的规则替换为
时会发生完全相同的行为for a in range(100):
s = re.sub(r'(?i)caught here'+str(a)+':.+', r'( ... )', s)
当改用 range(101) 时,它慢了 20 倍。
# range(100)
% ./dashlog.py file.bz2
== Took 2.1 seconds. ==
# range(101)
% ./dashlog.py file.bz2
== Took 47.6 seconds. ==
为什么会发生这样的事情? 是否有任何已知的解决方法?
(在 Linux/Windows 上的 Python 2.6.6/2.7.2 上发生。)
最佳答案
Python 为已编译的正则表达式保留一个内部缓存。每当您使用采用正则表达式的顶级函数之一时,Python 都会首先编译该表达式,并缓存该编译的结果。
Guess how many items the cache can hold ?
>>> import re
>>> re._MAXCACHE
100
当您超过缓存大小时,Python 2 清除所有缓存的表达式并从一个干净的缓存开始。 Python 3 将限制增加到 512,但仍然完全清除。
解决方法是让您自己缓存编译:
compiled_expression = re.compile(r'(?i)User [_0-9A-z]+ is ')
compiled_expression.sub(r"User .. is ", s)
您可以使用 functools.partial()
将 sub()
调用与替换表达式捆绑在一起:
from functools import partial
compiled_expression = re.compile(r'(?i)User [_0-9A-z]+ is ')
ready_to_use_sub = partial(compiled_expression.sub, r"User .. is ")
然后稍后使用 ready_to_use_sub(s)
将编译后的正则表达式模式与特定的替换模式一起使用。
关于当循环超过 100 个不同的正则表达式时,Python re 模块变得慢 20 倍,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17325281/