在Python中编译正则表达式

时间:2013-02-07 16:22:14

标签: python regex compilation

我正在研究Doug Hellman的“示例中的Python标准库”,并且遇到了这个:

“1.3.2编译表达式 re包含用于将正则表达式作为文本字符串处理的模块级函数,但编译程序经常使用的表达式更有效。“

我不能按照他的解释为什么会这样。他说“模块级函数维护已编译表达式的缓存”,并且由于“缓存大小”有限,“使用编译表达式直接避免了缓存查找开销。”

如果有人能够解释或指导我解释一下我能更好地理解为什么编译程序经常使用的正则表达式以及这个过程实际如何工作的原因,我会非常感激。 p>

3 个答案:

答案 0 :(得分:8)

嗯。这很奇怪。到目前为止,我的知识(获得,以及其他来源,from this question)提出了我的初步答案:


第一个答案

Python缓存您使用的最后100个正则表达式,因此即使您没有显式编译它们,也不必在每次使用时重新编译它们。

但是,有两个缺点:当达到100个正则表达式的限制时,整个缓存都会被破坏,因此如果连续使用101个不同的正则表达式,每次都会重新编译每个正则表达式。嗯,这不太可能,但仍然。

其次,为了找出是否已经编译了正则表达式,解释器需要每次都在缓存中查找正则表达式,这需要花费一点额外的时间(但由于字典查找速度非常快)。

因此,如果您显式编译正则表达式,则可以避免这个额外的查找步骤。


更新

我刚做了一些测试(Python 3.3):

>>> import timeit
>>> timeit.timeit(setup="import re", stmt='''r=re.compile(r"\w+")\nfor i in range(10):\n r.search("  jkdhf  ")''')
18.547793477671938
>>> timeit.timeit(setup="import re", stmt='''for i in range(10):\n re.search(r"\w+","  jkdhf  ")''')
106.47892003890324

所以似乎没有进行缓存。也许这是timeit.timeit()运行的特殊条件的怪癖?

另一方面,在Python 2.7中,差异并不明显:

>>> import timeit
>>> timeit.timeit(setup="import re", stmt='''r=re.compile(r"\w+")\nfor i in range(10):\n r.search("  jkdhf  ")''')
7.248294908492429
>>> timeit.timeit(setup="import re", stmt='''for i in range(10):\n re.search(r"\w+","  jkdhf  ")''')
18.26713670282241

答案 1 :(得分:4)

我相信他想说的是你不应该在你的循环中编译你的正则表达式,而是在它之外。然后,您可以在循环中运行已编译的代码。

而不是:

while true: 
    result = re.match('A', str)

你应该把:

regex = re.compile('A')
while true:
    result = regex.match(str)

基本上re.match(pattern, str)结合了编译和匹配步骤。在循环内编译相同的模式是低效的,因此应该在循环外部提升。

请参阅Tim对正确推理的回答。

答案 2 :(得分:0)

听起来像作者只是说编译正则表达式更有效率并保存它比依赖于以前编译的版本仍然保留在模块的有限大小的内部缓存中。这可能是因为编译它们所需的工作量加上必须首先发生的额外缓存查找开销大于客户端只是自己存储它们。