正则表达式re.findall()挂起 - 如果你不能逐行阅读怎么办?

时间:2013-04-04 20:08:46

标签: python regex hang

我有多个文件,每个文件都在搜索一系列文字。

我的正则表达式基本上搜索一个序列,其中word1后跟word2,后跟word 3等。 所以表达式如下:

strings = re.findall('word1.*?word2.*?word3', f.read(), re.DOTALL)

对于低于20kb的文件,表达式执行得非常好。但是,文件的执行时间呈指数增长> 20 kb,该过程完全挂起接近100kb的文件。 看起来(在阅读了之前的线程之后)问题与使用。*和re.DOTALL一起使用 - 导致“灾难性的回溯”。建议的解决方案是逐行提供输入文件,而不是将整个文件读入单个内存缓冲区。

但是,我的输入文件中填充了随机空格和“\ n”换行符。我的单词序列也很长并且发生在多行上。因此,我需要将整个文件与re.DOTALL一起输入到regex表达式中 - 否则逐行搜索将永远不会找到我的序列。

周围有什么办法吗?

3 个答案:

答案 0 :(得分:2)

如果你真的在搜索三个单词的出现,根本没有正则表达式模式,根本就没有必要使用正则表达式 - 正如@Bart所建议的那样,我写了这个答案:)。像这样的东西可能会起作用(未经测试,可能更漂亮):

with open('...') as f:
    contents = f.read()

words = ['word1', 'word2', 'word3']
matches = []
start_idx = 0
try:
    while True:
        cand = []
        for word in words:
            word_idx = contents.index(word, start_idx)
            cand.append(word_idx)
            start_idx = word_idx + len(word)
        matches.append(cand)
except ValueError:  # from index() failing
    pass

这将指数放在matches;如果你想要一个等效的结果,你可以做,比方说,

found = [contents[match[0]:match[-1]+len(words[-1]] for match in matches]

您也可以通过使用文件上的等效函数替换对index的调用来预先读取整个文件,从而使这种方法工作。我不认为stdlib包含这样的功能;你可能不得不在文件对象上手动使用readline()tell()或类似的方法。

答案 1 :(得分:1)

发生这种情况的原因是因为python的正则表达式引擎使用了回溯。在每.*,如果找不到下面的单词,引擎必须一直到字符串的末尾(100kb),然后回溯。现在考虑如果在最后一场比赛后有很多“几乎匹配”会发生什么。引擎从匹配开始到字符串结尾不断跳来跳去。

您可以使用基于NFA而非回溯的正则表达式引擎来修复它。请注意,这限制了您可以使用的正则表达式的类型(没有回溯或任意零宽度断言),但它适用于您的用例。

您可以找到这样的引擎here。您可以在www.debuggex.com处可视化nfa引擎的工作原理。

答案 2 :(得分:0)

您可以使用循环一次搜索一个单词。我在这里使用str.find(),因为它对于简单的子字符串搜索更快,但您也可以调整此代码以使用re.search()代替。

def findstrings(text, words):
    end = 0
    while True:
        start = None
        for word in words:
            pos = text.find(word, end) #starts from position end
            if pos < 0:
                return
            if start is None:
                start = pos
            end = pos + len(word)
        yield text[start:end]


#usage in place of re.findall('word1.*?word2.*?word3', f.read(), re.DOTALL)
list(findstrings(f.read(), ['word1', 'word2', 'word3']))