python中许多正则表达式的速度

时间:2009-11-23 11:32:23

标签: python regex performance

我正在编写一个处理大量字符串/文件的python程序。我的问题是,我将会收到一段相当短的文本,我将需要搜索相当广泛的单词/短语的实例。

我想我需要编译正则表达式作为在文本中匹配这些单词/短语的方法。但是,我担心的是,这需要花费很多时间。

我的问题是,重复编译正则表达式,然后搜索一小段文本以查找匹配的过程有多快?我会更好地使用一些字符串方法吗?

编辑:所以,我想我的问题的一个例子是:用一个正则表达式编译和搜索的成本是多少,而不是说,在字符串中迭代'if“字,说5次?

9 个答案:

答案 0 :(得分:5)

如果速度至关重要,那么在决定如何编写生产应用程序代码之前,最好先运行一些测试。

首先,你说你正在搜索的单词表明你可以使用split()来分解空格上的字符串。然后使用简单的字符串比较来进行搜索。

绝对要编译正则表达式并进行时序测试,将其与普通字符串函数进行比较。查看字符串类的文档以获取完整列表。

答案 1 :(得分:5)

您应该尝试使用|运算符将所有正则表达式编译为单个正则表达式。这样,regexp引擎将为您完成大部分优化。使用分组运算符()来确定匹配的正则表达式。

答案 2 :(得分:3)

您的要求似乎是在文本中搜索任何一个字符串集合的第一次出现。据推测,您希望重新启动搜索以查找下一个匹配项,依此类推,直到搜索到的字符串用完为止。只涉及普通的旧字符串比较。

此任务的经典算法是Aho-Corasick,其中有Python extension(用C语言编写)。这应该击败使用re模块的任何替代方案。

答案 3 :(得分:2)

如果您想知道在编译正则表达式模式时它是如何快速的,您需要对其进行基准测试。

我是这样做的。每个模式编译1百万次。

import time,re

def taken(f):
 def wrap(*arg):
  t1,r,t2=time.time(),f(*arg),time.time()
  print t2-t1,"s taken"
  return r
 return wrap

@taken
def regex_compile_test(x):
 for i in range(1000000):
  re.compile(x)
 print "for",x,

#sample tests
regex_compile_test("a")
regex_compile_test("[a-z]")
regex_compile_test("[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}")

我的电脑每个模式花了大约5分钟。

for a 4.88999986649 s taken
for [a-z] 4.70300006866 s taken
for [A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4} 4.78200006485 s taken

真正的瓶颈不在于编译模式,而是在提取 re.findall 等文本,替换 re.sub 。如果你对几个MB文本使用它,它很慢。

如果文本是固定的,请使用普通的str.find,它比正则表达式更快。<​​/ p>

实际上,如果你给你的文本样本和你的正则表达式模式样本,我们可以给你更好的想法,有很多伟大的正则表达式,以及那里的python人。

希望得到这个帮助,对不起如果我的回答无法帮助你。

答案 4 :(得分:2)

这个问题可以通过尝试来轻松回答。

>>> import re
>>> import timeit
>>> find = ['foo', 'bar', 'baz']
>>> pattern = re.compile("|".join(find))
>>> with open('c:\\temp\\words.txt', 'r') as f:
        words = f.readlines()

>>> len(words)
235882
>>> timeit.timeit('r = filter(lambda w: any(s for s in find if w.find(s) >= 0), words)', 'from __main__ import find, words', number=30)
18.404569854548527
>>> timeit.timeit('r = filter(lambda w: any(s for s in find if s in w), words)', 'from __main__ import find, words', number=30)
10.953313759150944
>>> timeit.timeit('r = filter(lambda w: pattern.search(w), words)', 'from __main__ import pattern, words', number=30)
6.8793022576891758

看起来你可以合理地期望正则表达式比使用findin更快。虽然如果我是你,我会用一个更像你真实数据的案例重复这个测试。

答案 5 :(得分:1)

编译正则表达式时,它将转换为状态机表示形式。如果有效表达正则表达式,它仍然应该非常快速地匹配。编译正则表达式可能很昂贵,所以你需要预先做到这一点,尽可能不频繁。但最终,只有你能够快速满足你的要求才能回答。

还有其他字符串搜索方法,例如Boyer-Moore algorithm。但我敢打赌,搜索多个单独字符串的复杂性远远高于可以关闭每个连续字符的正则表达式。

答案 6 :(得分:0)

如果您只是搜索特定的子字符串,请改用str.find()

答案 7 :(得分:0)

根据你正在做的事情,最好使用一个标记器并遍历标记来查找匹配。

然而,当谈到短片时,正则表达式具有令人难以置信的良好性能。就个人而言,我记得只有当文字大小变得像100k字或类似的东西一样荒谬时才会出现问题。

此外,如果您担心实际正则表达式编译的速度而不是匹配,您可能会受益于创建一个守护进程,该守护进程编译所有正则表达式然后遍历大循环中的所有文本或作为服务运行。这样,您只需编译一次正则表达式。

答案 8 :(得分:0)

一般情况下,您可以使用“in”关键字

for line in open("file"):
    if "word" in line:
        print line.rstrip()
使用Python时通常不需要

正则表达式:)