为什么要搜索> 100个不同的正则表达式使我的python脚本慢慢爬行?

时间:2014-05-28 16:38:10

标签: python regex performance

我见过有关Python的线程不接受超过100组的正则表达式。我有一个类似但(我认为?)不同的问题。

我有一个我为工作编写的python脚本,用于在大型(10-100MB)复杂日志文件中查找“有趣”的东西。我有一个字符串列表,其中每个字符串在调用re.search时用作正则表达式。每个正则表达式在每行日志记录中逐个运行。当我的列表有100个或更少的正则表达式字符串时,一切都运行peachy。但是当我在列表中再添加一个时,脚本运行得如此之慢以至于无用。

我写了一个模拟问题的简短脚本。有人可以帮我确定为什么会发生这种情况,并就我能做些什么提出一些建议吗?

以下是来自下面脚本的一些示例输出。我运行脚本的日志很少少于250,000行,通常是1-2百万行。

$ ./regexTest.py 100 10000
Running regex search
Done regex search
Time Elapsed: 0.734515 seconds

$ ./regexTest.py 101 10000
Running regex search
Done regex search
Time Elapsed: 44.428968 seconds

谢谢大家的时间!


#!/usr/bin/python
#------------------------------------------------------------------------------
# File: regexTest.py
# Description: Simulate the problem where trying to use a list of more than
#              100 regular expression strings slows the script to uselessness
# Example:
#   ./regexTest.py 100 10000
#   ./regexTest.py 101 10000
#------------------------------------------------------------------------------

from random import randint
import re
import sys
import time

def main():
    if (len(sys.argv) != 3):
        print "Usage: %s <NUM REGEXES> <LOG FILE LENGTH>" % sys.argv[0]
        sys.exit(1)

    numRegexes    = int(sys.argv[1])
    logFileLength = int(sys.argv[2])

    regexes = []

    # generate random regular expressions comprised of between 5 and 20
    # lowercase letters
    for i in range(numRegexes):
        randomLetters = [chr(randint(97,120)) for x in range(randint(5,20))]
        baseRegex     = "".join(randomLetters)
        regex         = baseRegex + str(i)

        regexes.append(regex)

    # simulate the contents of a log file
    data = []
    for i in range(logFileLength):
        randomLetters = [chr(randint(97,120)) for x in range(randint(20,100))]
        logLine       = "".join(randomLetters)

        data.append(logLine)

    print "Running regex search"
    startTime = time.time()

    for line in data:
        for regex in regexes:
            ret = re.search(regex, line)
            if (ret is not None):
                print "Regex found"

    print "Done regex search"
    endTime = time.time()

    print "Time Elapsed: %f seconds" % (endTime - startTime)

if (__name__ == "__main__"):
    main()

1 个答案:

答案 0 :(得分:2)

你正在使用正则表达式错误;你应该编译它们。 re模块中有一个缓存,用于不编译正则表达式的懒人; Python 2.7上的缓存大小为100,Python 3.4上为512。 re._MAXCACHE可以使用缓存大小。在这100个条目用尽之后,所有编译模式将从缓存中排除。如果您发现自己的程序使用的re._MAXCACHE以上版本正常,则应使用re.compile对其进行预编译。

regexes = [ re.compile(i) for i in regexes ]
for line in data:
    for regex in regexes:
        ret = regex.search(line)
        if ret is not None:
            print("Regex found")

此外,如果您确实没有使用任何这些匹配项,则应将它们合并为一个。因此,您可以尝试将它们加入&#39; |&#39; bar运算符使它们彼此替代:

megaregex = re.compile('|'.join(regexes))
for line in data:
    ret = megaregex.search(line)
    if ret is not None:
        print("Regex found")