在Python中对正则表达式使用compile有什么好处吗?

h = re.compile('hello')
h.match('hello world')

vs

re.match('hello', 'hello world')

当前回答

一般来说,我发现在编译模式时使用标志比内联使用标志更容易(至少更容易记住如何使用),比如re.I。

>>> foo_pat = re.compile('foo',re.I)
>>> foo_pat.findall('some string FoO bar')
['FoO']

vs

>>> re.findall('(?i)foo','some string FoO bar')
['FoO']

其他回答

对我来说,re.compile的最大好处是能够将正则表达式的定义与其使用分开。

即使是一个简单的表达式,如0|[1-9][0-9]*(以10为基数,不带前导零的整数),也可能非常复杂,以至于您宁愿不重新输入它,检查是否有任何拼写错误,然后在开始调试时重新检查是否有拼写错误。另外,使用像num或num_b10这样的变量名比0|[1-9][0-9]*更好。

当然可以存储字符串并将它们传递给re.match;然而,这就不那么容易读了:

num = "..."
# then, much later:
m = re.match(num, input)

与编译:

num = re.compile("...")
# then, much later:
m = num.match(input)

虽然它很接近,但当重复使用时,第二句的最后一行感觉更自然、更简单。

有趣的是,编译对我来说确实更有效(Win XP上的Python 2.5.2):

import re
import time

rgx = re.compile('(\w+)\s+[0-9_]?\s+\w*')
str = "average    2 never"
a = 0

t = time.time()

for i in xrange(1000000):
    if re.match('(\w+)\s+[0-9_]?\s+\w*', str):
    #~ if rgx.match(str):
        a += 1

print time.time() - t

按原样运行上述代码一次,并以相反的方式运行两个if行,编译后的正则表达式的速度将提高一倍

抛开性能差异不考虑,使用re.compile和使用编译后的正则表达式对象进行匹配(任何与正则表达式相关的操作)使得Python运行时的语义更加清晰。

我有过调试一些简单代码的痛苦经历:

compare = lambda s, p: re.match(p, s)

然后我用compare in

[x for x in data if compare(patternPhrases, x[columnIndex])]

其中patternPhrases应该是一个包含正则表达式字符串的变量,x[columnIndex]是一个包含字符串的变量。

我有麻烦,patternPhrases不匹配一些预期的字符串!

但是如果我使用re.compile形式:

compare = lambda s, p: p.match(s)

然后在

[x for x in data if compare(patternPhrases, x[columnIndex])]

Python会抱怨“字符串没有匹配属性”,因为在compare中通过位置参数映射,x[columnIndex]被用作正则表达式!其实我的意思是

compare = lambda p, s: p.match(s)

在我的例子中,使用re.compile更明确地表达了正则表达式的目的,当它的值对肉眼隐藏时,因此我可以从Python运行时检查中获得更多帮助。

因此,我这一课的寓意是,当正则表达式不仅仅是字面字符串时,那么我应该使用re.compile让Python帮助我断言我的假设。

一般来说,我发现在编译模式时使用标志比内联使用标志更容易(至少更容易记住如何使用),比如re.I。

>>> foo_pat = re.compile('foo',re.I)
>>> foo_pat.findall('some string FoO bar')
['FoO']

vs

>>> re.findall('(?i)foo','some string FoO bar')
['FoO']

我有很多运行编译过的regex 1000的经验 与实时编译相比,并没有注意到 任何可感知的差异

对已接受答案的投票导致假设@Triptych所说的对所有情况都是正确的。这并不一定是真的。一个很大的区别是当你必须决定是接受一个正则表达式字符串还是一个编译过的正则表达式对象作为函数的参数时:

>>> timeit.timeit(setup="""
... import re
... f=lambda x, y: x.match(y)       # accepts compiled regex as parameter
... h=re.compile('hello')
... """, stmt="f(h, 'hello world')")
0.32881879806518555
>>> timeit.timeit(setup="""
... import re
... f=lambda x, y: re.compile(x).match(y)   # compiles when called
... """, stmt="f('hello', 'hello world')")
0.809190034866333

编译正则表达式总是更好的,以防需要重用它们。

请注意,上面timeit中的示例模拟在导入时一次创建已编译的regex对象,而不是在需要匹配时“动态”创建。