如何从Python中的文本文件中解析不同数量的行?

时间:2014-11-26 16:07:54

标签: python regex parsing text-files

我正在尝试编写一个简单的解析器,它从一个.txt文件中抓取多行文本块并将其复制到新的.txt文件中。为什么(我认为)我的问题与在线发布的类似问题的不同之处在于,行数因文本块而异,所以我需要某种方法来识别所需文本块的开始和结束位置。

考虑输入文件的这个最小示例:

NAME_1{a bunch of text|more text}
 1  -22.17
1 lol //
2 wtf //
NA_ME2{text|text}
 1  -25.50
1 gtfo //
NAME3{text|text}
 1  -17.50
1 brb //
2 lol //
3 wtf //

我希望我的解析器输出一个带有NAME_1及其所有相关信息的文本文件,以及NAME3及其所有相关信息。我想要输出文本文件:

NAME_1{a bunch of text|more text}
 1  -22.17
1 lol //
2 wtf //
NAME3{text|text}
 1  -17.50
1 brb //
2 lol //
3 wtf //

我有一个有效的解析器但是有问题(并且效率低下,但我是新手)。具体来说,我需要的大多数文本块长度为43行,因此我的解析器识别所需的名称,然后抓取该行和接下来的42行文本。但这是一个问题,因为一些文本块的长度不是43行。这就是我到目前为止所做的:

import re

infile = open('input.txt')
outfile = open('output.txt', 'w')

# Appends all needed names into a list
nameList = []
with open('list.txt') as f:
for name in f:
    n = name.strip()
    nameList.append(n)

# Finds required name from example txt file and outputs that line and the next 42   
lines = infile.readlines()
for line in range(0,len(lines)):
    for l in nameList:
        if l in lines[line]:
         [outfile.write(part) for part in lines[line:line+42]]

list.txt文件包含以下内容:

NAME_1{
NAME3{

我认为正则表达式可以解决我的问题。 '([A-Z]\w+){'将找到每个文本块的开头,所以我想必须有一些方法来确定RE匹配是否等同于nameList项,然后解析每一行直到 - 但不包括 - '([A-Z]\w+){'的下一场比赛。这样一来,文本块的长度不应该是多少。是否有可能以这种方式使用正则表达式识别所需的文本块的开始和结束位置?

感谢。

编辑:每个文本块都以正则表达式'([A-Z]\w+){'的出现开头。因此,示例输入文件包含三个文本块,其中带有NAME_1,NA_ME2和NAME3的行代表每个块的第一行。

1 个答案:

答案 0 :(得分:0)

试试这个:

import re

s = """NAME_1{a bunch of text|more text}
 1  -22.17
1 lol //
2 wtf //
NA_ME2{text|text}
 1  -25.50
1 gtfo //
NAME3{text|text}
 1  -17.50
1 brb //
2 lol //
3 wtf //
"""

guards = ["NAME_1", "NAME3"]    
r = re.compile(r"^([A-Z][A-Z0-9_]+){")
printing = False

for line in s.splitlines():
    m = r.match(line)
    if m:
        if m.groups(1) and m.groups(1)[0] in guards:
            printing = True
        else:
            printing = False
    if printing:
        print(line.strip())

输出:

NAME_1{a bunch of text|more text}
1  -22.17
1 lol //
2 wtf //
NAME3{text|text}
1  -17.50
1 brb //
2 lol //
3 wtf //