Python读取文件直到匹配,读取到下一个模式为止。

3

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.

+++++++++++++++++++++ 更新 ++++++++++++++++++++++++++++++++

下面的代码是有效的,它会匹配头部类型行 - 输出该行及其后每一行直到下一个头部类型模式 - 如果不匹配则跳过直到下一个头部类型模式。

唯一的问题是 - 它非常非常慢。对于10m行而言,需要大约一分钟才能完成。

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中它没有被很好地实现。


我有点困惑你的问题。你是真的只是想在Python中模拟标准的sed、awk或perl行为,例如sed -ne '/foo/,/bar/p'perl -ne 'print if /foo/ .. /bar/',因为你需要一个简单的翻转操作符吗?请注意,.....是不同的,因为..在LHS变为true时立即测试RHS,而...则等到下一次。这就像++ii--之间的区别一样,它们是两个更基本的运算符,但你仍然必须从头开始重新编写它们。这个操作的整体应用是什么? - tchrist
2个回答

3

我认为在这里没有必要使用正则表达式。并不是说正则表达式很糟糕,但如果你只是寻找一个非常特定的模式,使用正则表达式就有点过头了。可以尝试类似这样的代码:

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

确切地说:记录生成器会产生包含换行符的行,因此您可能需要将它们连接在一起,而不添加任何额外的换行符:join
print "".join(list(record(filename, '---- Alpha ---- Zeta')))

谢谢Jellybean,我在这上面得到了一个无效的语法错误。并发现with open是2.5或更高版本。我使用的是2.4.3 - 很抱歉我没有在我的帖子中说明。 - Chasester
没问题,只需要将 with open(filename) as file 替换为 file = open(filename) - Johannes Charra
我认为它接近工作状态。它从第一个匹配的---- Alpha ---- Zeta开始打印,但是在下一个匹配的---- Alpha ---- Zeta之前打印所有内容,但不会将其打印出来。难道这不需要一种方法来告诉生成器一旦遇到不匹配的----类型行就停止记录/产生吗? - Chasester
啊,你想输出任何情况下的匹配行...好的,我会根据你的需求调整代码。 - Johannes Charra
我以为那正是你想要的 :) - Johannes Charra
显示剩余3条评论

2

您仍在匹配行,因为您仍处于for循环的同一次迭代中,而该行并未更改。


这实际上就是问题的全部所在 - 但它确实引起了我的注意,让我转向了一个循环。因此被接受的答案。 - Chasester

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接