我有一个巨大的文件,我需要从中获取特定条目的数据。文件结构是:
>Entry1.1
#size=1688
704 1 1 1 4
979 2 2 2 0
1220 1 1 1 4
1309 1 1 1 4
1316 1 1 1 4
1372 1 1 1 4
1374 1 1 1 4
1576 1 1 1 4
>Entry2.1
#size=6251
6110 3 1.5 0 2
6129 2 2 2 2
6136 1 1 1 4
6142 3 3 3 2
6143 4 4 4 1
6150 1 1 1 4
6152 1 1 1 4
>Entry3.2
#size=1777
AND SO ON-----------
我必须要实现的是我需要提取某些条目的所有行(完整记录)。对于e.x.我需要Entry1.1的记录,而不是我可以使用条目名称'> Entry1.1'直到下一个'>'作为REGEX中的标记来提取其间的线条。但我不知道如何构建这样复杂的REGEX表达式。一旦我有了这样的表达式,我就会把它换成FOR循环:
For entry in entrylist:
GET record from big_file
DO some processing
WRITE in result file
对于特定条目,可以执行此类记录提取的REGEX是什么?有没有更多的pythonic方法来实现这一目标?我很感激你的帮助。
AK
答案 0 :(得分:4)
使用正则表达式
import re
ss = '''
>Entry1.1
#size=1688
704 1 1 1 4
979 2 2 2 0
1220 1 1 1 4
1309 1 1 1 4
1316 1 1 1 4
1372 1 1 1 4
1374 1 1 1 4
1576 1 1 1 4
>Entry2.1
#size=6251
6110 3 1.5 0 2
6129 2 2 2 2
6136 1 1 1 4
6142 3 3 3 2
6143 4 4 4 1
6150 1 1 1 4
6152 1 1 1 4
>Entry3.2
#size=1777
AND SO ON-----------
'''
patbase = '(>Entry *%s(?![^\n]+?\d).+?)(?=>|(?:\s*\Z))'
while True:
x = raw_input('What entry do you want ? : ')
found = re.findall(patbase % x, ss, re.DOTALL)
if found:
print 'found ==',found
for each_entry in found:
print '\n%s\n' % each_entry
else:
print '\n ** There is no such an entry **\n'
'(>Entry *%s(?![^\n]+?\d).+?)(?=>|(?:\s*\Z))'
的解释:
%s
收到条目的引用:1.1,2,2.1等
部分(?![^\n]+?\d)
将进行验证。
(?![^\n]+?\d)
是一个负面的前瞻断言,表示%s
之后的内容不得为[^\n]+?\d
,也就是说数字[^\n]+?
之前的任何字符\d
1}}
我写[^\n]
表示“换行符\n
以外的任何字符”
我不得不写这个而不仅仅是.+?
,因为我放置了标志re.DOTALL
,模式部分.+?
将一直行动直到条目结束。
但是,我只想验证输入的参考(在模式中由%s表示)后,在错误输入的行结束之前不会有补充数字
所有这一切都是因为如果有一个Entry2.1但没有Entry2,并且用户只输入2因为他想要Entry2而没有其他,那么正则表达式会检测到Entry2.1的存在并且会产生它,尽管用户实际上非常喜欢Entry2。
在'(>Entry *%s(?![^\n]+?\d).+?)
结束时,部分.+?
将捕获条目的完整块,因为点代表任何字符,包含换行符\n
为了达到这个目的,我放置了标志re.DOTALL
,以便使以下模式部分.+?
能够传递换行符直到条目结束。
我希望匹配在所需条目的末尾停止,而不是在下一个条目的内部停止,以便由(>Entry *%s(?![^\n]+?\d).+?)
中的括号内定义的组将准确捕获我们想要的内容。
因此,我在最后给出了一个积极的外观断言(?=>|(?:\s*\Z))
,它表示运行的不合格.+?
必须停止匹配的字符是>
(下一个条目的开头) )或字符串\Z
的结尾
由于最后一个Entry的结尾可能不完全是整个字符串的结尾,我将\s*
表示“最终可能的空格”。
所以\s*\Z
意味着“在碰到字符串的末尾之前可能有空格”
空白是blank
,\f
,\n
,\r
,\t
,\v
答案 1 :(得分:1)
我对正则表达式不好,所以我尽力寻找非正则表达式解决方案。在Python中,存储迭代逻辑的自然位置在生成器中,因此我使用类似的东西(no-itertools-required version):
def group_by_marker(seq, marker):
group = []
# advance past negatives at start
for line in seq:
if marker(line):
group = [line]
break
for line in seq:
# found a new group start; yield what we've got
# and start over
if marker(line) and group:
yield group
group = []
group.append(line)
# might have extra bits left..
if group:
yield group
在您的示例中,我们得到:
>>> with open("entry0.dat") as fp:
... marker = lambda line: line.startswith(">Entry")
... for group in group_by_marker(fp, marker):
... print(repr(group[0]), len(group))
...
'>Entry1.1\n' 10
'>Entry2.1\n' 9
'>Entry3.2\n' 4
这种方法的一个优点是我们永远不必在内存中保留多个组,因此它对于非常大的文件很方便。它不像正则表达式那么快,虽然如果文件是1 GB,你可能无论如何都是I / O绑定。
答案 2 :(得分:0)
不完全确定你在问什么。这会让你更近吗?它会将您的所有条目作为字典键和所有条目的列表。假设它的格式与我相信的那样。它有重复的条目吗?这就是我所拥有的:
entries = {}
key = ''
for entry in open('entries.txt'):
if entry.startswith('>Entry'):
key = entry[1:].strip() # removes > and newline
entries[key] = []
else:
entries[key].append(entry)