我的输入文件是一个大型的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文件不应该太多,对吧? 我可能错过了更有效的解决方案吗?
提前致谢。
答案 0 :(得分:10)
您认为使用不止一次出现的序列.*
会导致问题,这是正确的。问题是解算器正在尝试.*
的许多可能组合,从而导致称为catastrophic backtracking的结果。
通常的解决方案是将.
替换为更具体的字符类,通常是您尝试终止第一个.*
的产品。类似的东西:
`[^\n]*(.*)`
这样捕获组只能匹配从第一个换行到结尾。另一种选择是认识到正则表达式解决方案可能不是最好的方法,并且可以使用无上下文表达式(例如pyparsing
),或者首先将输入分解为更小,更容易消化的块(例如,使用corpus.split('\n')
)
答案 1 :(得分:0)
此问题的另一个解决方法是对匹配字符的数量添加合理的限制。
所以不要这样:
[abc]*.*[def]*
您可以将其限制为每个字符组1-100个实例。
[abc]{1,100}.{1,100}[def]{1,100}
这并非在每种情况下都有效,但是在某些情况下,这是可以接受的快速修复程序。