Python读取文件直到匹配,继续读取到下一个模式
Python 2.4.3
我需要处理一些文件(可能大到10GB)。我想做的是遍历文件,直到找到一个特定的模式。然后打印出那一行以及之后的每一行,直到遇到另一个模式。到那时,再继续读取文件,直到下一个模式匹配。
举个例子,文件内容是这样的:
---- Alpha ---- Zeta
...(text lines)
---- Bravo ---- Delta
...(text lines)
等等。
如果要匹配的是 ---- Alpha ---- Zeta,那么它应该打印出 ---- Alpha ---- Zeta 以及之后的每一行,直到遇到 ---- Bravo ---- Delta(或者其他任何不是 ---- Alpha ---- Zeta 的内容),然后继续读取,直到再次匹配到 ---- Alpha ---- Zeta。
下面的代码符合我的需求,但只打印了匹配的那一行,而没有打印后面的内容。
你知道我哪里出错了吗?
import re
fh = open('text.txt', 'r')
re1='(-)' # Any Single Character 1
re2='(-)' # Any Single Character 2
re3='(-)' # Any Single Character 3
re4='(-)' # Any Single Character 4
re5='( )' # White Space 1
re6='(Alpha)' # Word 1
re6a='((?:[a-z][a-z]+))' # Word 1 alternate
re7='( )' # White Space 2
re8='(-)' # Any Single Character 5
re9='(-)' # Any Single Character 6
re10='(-)' # Any Single Character 7
re11='(-)' # Any Single Character 8
re12='(\\s+)' # White Space 3
re13='(Zeta)' # Word 2
re13a='((?:[a-z][a-z]+))' # Word 2 alternate
rg = re.compile(re1+re2+re3+re4+re5+re6+re7+re8+re9+re10+re11+re12+re13,re.IGNORECASE|re.DOTALL)
rga = re.compile(re1+re2+re3+re4+re5+re6a+re7+re8+re9+re10+re11+re12+re13a,re.IGNORECASE|re.DOTALL)
for line in fh:
if re.match(rg, line):
print line
fh.next()
while not re.match(rga, line):
print fh.next()
fh.close()
还有我的示例文本文件。
---- Pappa ---- Oscar
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris eleifend imperdiet
lacus quis imperdiet. Nulla erat neque, laoreet vel fermentum a, dapibus in sem.
Maecenas elementum nisi nec neque pellentesque ac rutrum urna cursus. Nam non purus
sit amet dolor fringilla venenatis. Integer augue neque, scelerisque ac dictum at,
venenatis elementum libero. Etiam nec ante in augue porttitor laoreet. Aenean ultrices
pellentesque erat, id porta nulla vehicula id. Cras eu ante nec diam dapibus hendrerit
in ac diam. Vivamus velit erat, tincidunt id tempus vitae, tempor vel leo. Donec
aliquam nibh mi, non dignissim justo.
---- Alpha ---- Zeta
Sed molestie tincidunt euismod. Morbi ultrices diam a nibh varius congue. Nulla velit
erat, luctus ac ornare vitae, pharetra quis felis. Sed diam orci, accumsan eget
commodo eu, posuere sed mi. Phasellus non leo erat. Mauris turpis ipsum, mollis sed
ismod nec, aliquam non quam. Vestibulum sem eros, euismod ut pharetra sit amet,
dignissim eget leo.
---- Charley ---- Oscar
Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.
Aliquam commodo, metus at vulputate hendrerit, dui justo tempor dui, at posuere
ante vitae lorem. Fusce rutrum nibh a erat condimentum laoreet. Nullam eu hendrerit
sapien. Suspendisse id lobortis urna. Maecenas ut suscipit nisi. Proin et metus at
urna euismod sollicitudin eu at mi. Aliquam ac egestas magna. Quisque ac vestibulum
lectus. Duis ac libero magna, et volutpat odio. Cras mollis tincidunt nibh vel rutrum.
Curabitur fringilla, ante eget scelerisque rhoncus, libero nisl porta leo, ac
vulputate mi erat vitae felis. Praesent auctor fringilla rutrum. Aenean sapien ligula,
imperdiet sodales ullamcorper ut, vulputate at enim.
---- Bravo ---- Delta
Donec cursus tincidunt pellentesque. Maecenas neque nisi, dignissim ac aliquet ac,
vestibulum ut tortor. Pellentesque habitant morbi tristique senectus et netus et
malesuada fames ac turpis egestas. Aenean ullamcorper dapibus accumsan. Aenean eros
tortor, ultrices at adipiscing sed, lobortis nec dolor. Fusce eros ligula, posuere
quis porta nec, rhoncus et leo. Curabitur turpis nunc, accumsan posuere pulvinar eget,
sollicitudin eget ipsum. Sed a nibh ac est porta sollicitudin. Pellentesque ut urna ut
risus pharetra mollis tincidunt sit amet sapien. Sed semper sollicitudin eros quis
pellentesque. Curabitur ac metus lorem, ac malesuada ipsum. Nulla turpis erat, congue
eu gravida nec, egestas id nisi. Praesent tellus ligula, pretium vitae ullamcorper
vitae, gravida eu ipsum. Cras sed erat ligula.
---- Alpha ---- Zeta
Cras id condimentum lectus. Sed sit amet odio eros, ut mollis sapien. Etiam varius
tincidunt quam nec mattis. Nunc eu varius magna. Maecenas id ante nisl. Cras sed augue
ipsum, non mollis velit. Fusce eu urna id justo sagittis laoreet non id urna. Nullam
venenatis tincidunt gravida. Proin mattis est sit amet dolor malesuada sagittis.
Curabitur in lacus rhoncus mi posuere ullamcorper. Phasellus eget odio libero, ut
lacinia orci. Pellentesque iaculis, ligula at varius vulputate, arcu leo dignissim
massa, non adipiscing lectus magna nec dolor. Quisque in libero nec orci vestibulum
dapibus. Nulla turpis massa, varius quis gravida eu, bibendum et nisl. Fusce tincidunt
laoreet elit, sed egestas diam pharetra eget. Maecenas lacus velit, egestas nec tempor
eget, hendrerit et massa.
+++++++++++++++++++++ 更新 ++++++++++++++++++++++++++++++++
以下代码是有效的 - 它在标题类型的行上匹配 - 打印出那一行以及之后的每一行,直到下一个标题类型的模式 - 如果不匹配,就跳过,直到下一个标题类型的模式。
唯一的问题是 - 它真的非常慢。处理1000万行大约需要一分钟。
re1='(-)' # Any Single Character 1
re2='(-)' # Any Single Character 2
re3='(-)' # Any Single Character 3
re4='(-)' # Any Single Character 4
re5='( )' # White Space 1
re6='(Alpha)' # Word 1
re6a='((?:[a-z][a-z]+))' # Word 1 alternate
re7='( )' # White Space 2
re8='(-)' # Any Single Character 5
re9='(-)' # Any Single Character 6
re10='(-)' # Any Single Character 7
re11='(-)' # Any Single Character 8
re12='(\\s+)' # White Space 3
re13='(Zeta)' # Word 2
re13a='((?:[a-z][a-z]+))' # Word 2 alternate
rg = re.compile(re1+re2+re3+re4+re5+re6+re7+re8+re9+re10+re11+re12+re13,re.IGNORECASE|re.DOTALL)
rga = re.compile(re1+re2+re3+re4+re5+re6a+re7+re8+re9+re10+re11+re12+re13a,re.IGNORECASE|re.DOTALL)
linestop = 0
fh = open('test.txt', 'r')
for line in fh:
if linestop == 0:
if re.match(rg, line):
print line
linestop = 1
else:
if re.match(rga, line):
linestop = 0
else:
print line
fh.close()
+++++++++ 如果我先加一个grep部分,我想这会大大加快速度。也就是说,先用grep筛选,然后再运行上面的正则表达式脚本。
我用os.system运行得很好 - 但我不知道怎么通过pOpen传递正则匹配。
**** 最终更新 **********
我把这个任务算完成了。我最终做的是:
- 使用os.system对文件进行grep处理,并将结果写出。
- 读取文件并使用我上面提到的re.match,只打印出必要的内容。
最终结果是,从处理一个1000万行的文件,打印出必要内容的时间从大约65秒减少到3.5秒。我希望我能找到除了os.system以外的其他方法来传递grep,但可能在Python 2.4中实现得不太好。
2 个回答
我觉得在这里用正则表达式没必要。正则表达式虽然不是特别糟糕,但如果你只是想找一个特定的模式,用它就有点过了。你可以试试下面这种方法:
def record(filename, pattern):
with open(filename) as file:
recording = False
for line in file:
if line.startswith(pattern):
yield line
recording = not recording
elif recording:
yield line
调用 record
函数,传入文件名和你的模式,会得到一个生成器对象,它会一行一行地给你输出内容。这样处理大文件会更好,因为你不需要一次性把整个文件都读进来。
打印你的行可以这样做——假设你的文件名是 example.txt
:
for rec in record(filename, '---- Alpha ---- Zeta'):
print rec
具体来说:record
生成器会输出每一行,包括换行符,所以你可能需要把它们用 join
方法重新连接起来,确保没有多余的换行:
print "".join(list(record(filename, '---- Alpha ---- Zeta')))
你还是在和 line 进行比较,但因为你还在 for 循环的同一次迭代中,所以 line 的内容没有变化。