re.findall正则表达式挂起或非常慢

时间:2012-03-28 00:25:47

标签: python regex

我的输入文件是一个大型的txt文件,其中包含我从开放文本库中获得的连接文本。我现在正试图仅提取书本身的内容并过滤掉其他内容,例如免责声明等。所以我在我的大文本文件中大约有100个文档(大约50 mb)。

然后我确定了内容本身的开始和结束标记,并决定使用Python正则表达式找到开始和结束标记之间的所有内容。总而言之,正则表达式应该查找开始标记,然后匹配它后面的所有内容,并在达到结束标记后停止查找,然后重复这些步骤,直到到达文件末尾。

当我将一个100kb的小型文件输入其中时,以下代码可以正常运行:

import codecs
import re

outfile = codecs.open("outfile.txt", "w", "utf-8-sig")
inputfile = codecs.open("infile.txt", "r", "utf-8-sig")
filecontents = inputfile.read()
for result in re.findall(r'START\sOF\sTHE\sPROJECT\sGUTENBERG\sEBOOK.*?\n(.*?)END\sOF\THE\sPROJECT\sGUTENBERG\sEBOOK', filecontents, re.DOTALL):
    outfile.write(result)
outfile.close()

当我在我的较大文件上使用此正则表达式操作时,它不会执行任何操作,程序只会挂起。我在一夜之间进行了测试,看它是否只是很慢,甚至在大约8小时后程序仍然停滞不前。

我非常确定问题的根源是     (。*?) 正则表达式的一部分,与re.DOTALL结合使用。 当我在较小距离上使用类似的正则表达式时,脚本将运行良好且快速。 我现在的问题是:为什么这会冻结一切?我知道分隔符之间的文本不小,但50mb文件不应该太多,对吧? 我可能错过了更有效的解决方案吗?

提前致谢。

2 个答案:

答案 0 :(得分:10)

您认为使用不止一次出现的序列.*会导致问题,这是正确的。问题是解算器正在尝试.*的许多可能组合,从而导致称为catastrophic backtracking的结果。

通常的解决方案是将.替换为更具体的字符类,通常是您尝试终止第一个.*的产品。类似的东西:

`[^\n]*(.*)`

这样捕获组只能匹配从第一个换行到结尾。另一种选择是认识到正则表达式解决方案可能不是最好的方法,并且可以使用无上下文表达式(例如pyparsing),或者首先将输入分解为更小,更容易消化的块(例如,使用corpus.split('\n')

答案 1 :(得分:0)

此问题的另一个解决方法是对匹配字符的数量添加合理的限制。

所以不要这样:

[abc]*.*[def]*

您可以将其限制为每个字符组1-100个实例。

[abc]{1,100}.{1,100}[def]{1,100}

这并非在每种情况下都有效,但是在某些情况下,这是可以接受的快速修复程序。