当循环超过 100 个不同的正则表达式时,Python re 模块变得慢 20 倍

标签 python regex performance

我的问题是关于解析日志文件并删除每一行的可变部分以便对它们进行分组。例如:

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/

相关文章:

python - 将数组的数组转换为 NumPy 的 ndarray of ndarrays

Javascript 函数使用正则表达式删除字符串中的所有数字

javascript - 删除 Div 标签的正则表达式

performance - Kotlin中的get和[]有什么区别?

performance - 如何在不牺牲性能的情况下将函数作为参数传递给Julia中的其他函数?

python - 如何将列表附加到空的 numpy 数组

python - 如何使用 python3、CircleCI 和 Mayavi 对图形进行单元测试

python - 当规范坚持时如何避免类耦合

regex - 使用正则表达式从源代码中提取逗号分隔的单元

python - Cassandra Spark 写入速度慢