在超过100个不同的正则表达式上循环时,Python re模块的速度降低了20倍

发布于 2021-01-29 17:34:58

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

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上。)

关注者
0
被浏览
50
1 个回答
  • 面试哥
    面试哥 2021-01-29
    为面试而生,有面试问题,就找面试哥。

    Python为已编译的正则表达式保留内部缓存。每当使用带正则表达式的顶级函数之一时,Python都会首先编译该表达式,然后缓存该编译结果。

    猜猜缓存可以容纳多少个项目

    >>> 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)用于将编译后的正则表达式模式与特定的替换模式一起使用。



知识点
面圈网VIP题库

面圈网VIP题库全新上线,海量真题题库资源。 90大类考试,超10万份考试真题开放下载啦

去下载看看