在格式化的文本文件中查找文本块
Posted
技术标签:
【中文标题】在格式化的文本文件中查找文本块【英文标题】:Find a block of text in formatted text file 【发布时间】:2014-08-08 13:34:04 【问题描述】:我经常使用 Python 解析格式化的文本文件(用于生物学研究,但我会尝试以您不需要生物学背景的方式提出我的问题。)我处理一种文件类型 - 称为 pdb 文件 -在格式化文本中包含蛋白质的 3D 结构。这是一个例子:
HEADER CHROMOSOMAL PROTEIN 02-JAN-87 1UBQ
TITLE STRUCTURE OF UBIQUITIN REFINED AT 1.8 ANGSTROMS RESOLUTION
REMARK 1
REMARK 1 REFERENCE 1
REMARK 1 AUTH S.VIJAY-KUMAR,C.E.BUGG,K.D.WILKINSON,R.D.VIERSTRA,
REMARK 1 AUTH 2 P.M.HATFIELD,W.J.COOK
REMARK 1 TITL COMPARISON OF THE THREE-DIMENSIONAL STRUCTURES OF HUMAN,
REMARK 1 TITL 2 YEAST, AND OAT UBIQUITIN
REMARK 1 REF J.BIOL.CHEM. V. 262 6396 1987
REMARK 1 REFN ISSN 0021-9258
ATOM 1 N MET A 1 27.340 24.430 2.614 1.00 9.67 N
ATOM 2 CA MET A 1 26.266 25.413 2.842 1.00 10.38 C
ATOM 3 C MET A 1 26.913 26.639 3.531 1.00 9.62 C
ATOM 4 O MET A 1 27.886 26.463 4.263 1.00 9.62 O
ATOM 5 CB MET A 1 25.112 24.880 3.649 1.00 13.77 C
ATOM 6 CG MET A 1 25.353 24.860 5.134 1.00 16.29 C
ATOM 7 SD MET A 1 23.930 23.959 5.904 1.00 17.17 S
ATOM 8 CE MET A 1 24.447 23.984 7.620 1.00 16.11 C
ATOM 9 N GLN A 2 26.335 27.770 3.258 1.00 9.27 N
ATOM 10 CA GLN A 2 26.850 29.021 3.898 1.00 9.07 C
ATOM 11 C GLN A 2 26.100 29.253 5.202 1.00 8.72 C
ATOM 12 O GLN A 2 24.865 29.024 5.330 1.00 8.22 O
ATOM 13 CB GLN A 2 26.733 30.148 2.905 1.00 14.46 C
ATOM 14 CG GLN A 2 26.882 31.546 3.409 1.00 17.01 C
ATOM 15 CD GLN A 2 26.786 32.562 2.270 1.00 20.10 C
ATOM 16 OE1 GLN A 2 27.783 33.160 1.870 1.00 21.89 O
ATOM 17 NE2 GLN A 2 25.562 32.733 1.806 1.00 19.49 N
ATOM 18 N ILE A 3 26.849 29.656 6.217 1.00 5.87 N
ATOM 19 CA ILE A 3 26.235 30.058 7.497 1.00 5.07 C
ATOM 20 C ILE A 3 26.882 31.428 7.862 1.00 4.01 C
ATOM 21 O ILE A 3 27.906 31.711 7.264 1.00 4.61 O
ATOM 22 CB ILE A 3 26.344 29.050 8.645 1.00 6.55 C
ATOM 23 CG1 ILE A 3 27.810 28.748 8.999 1.00 4.72 C
ATOM 24 CG2 ILE A 3 25.491 27.771 8.287 1.00 5.58 C
ATOM 25 CD1 ILE A 3 27.967 28.087 10.417 1.00 10.83 C
TER 26 ILE A 3
HETATM 604 O HOH A 77 45.747 30.081 19.708 1.00 12.43 O
HETATM 605 O HOH A 78 19.168 31.868 17.050 1.00 12.65 O
HETATM 606 O HOH A 79 32.010 38.387 19.636 1.00 12.83 O
HETATM 607 O HOH A 80 42.084 27.361 21.953 1.00 22.27 O
END
ATOM
标记包含原子坐标的行的开头。 TER
标记坐标结束。我想获取包含原子坐标的整个文本块,所以我使用:
import re
f = open('example.pdb', 'r+')
content = f.read()
coor = re.search('ATOM.*TER', content) #take everthing between ATOM and TER
但它什么都不匹配。必须有一种使用正则表达式来获取整个文本块的方法。我也不明白为什么这个正则表达式模式不起作用。感谢您的帮助。
【问题讨论】:
【参考方案1】:这应该匹配(但我还没有实际测试过):
coor = re.search('ATOM.*TER', content, re.DOTALL)
如果您阅读了documentation on DOTALL
,您就会明白为什么它不起作用。
上面写的更好的方法是
coor = re.search(r'^ATOM.*^TER', content, re.MULTILINE | re.DOTALL)
要求ATOM
和TER
出现在换行符之后,以及使用raw string notation 的位置,这是正则表达式的惯例(尽管在这种情况下不会有任何区别)。
您也可以完全避免使用正则表达式:
start = content.index('\nATOM')
end = content.index('\nTER', start)
coor = content[start:end]
(这实际上不会在结果中包含TER
,这可能会更好)。
【讨论】:
感谢您的回复。我绝对应该检查 re.DOTALL。这完全符合我最初的意图。没有正则表达式的选项也不能正常工作,因为文件中可能有多个 ATOM ... TER 块,据我所知,它只提供到第一个 TER。【参考方案2】:你需要(?s)
修饰符:
import re
f = open('example.pdb', 'w+')
content = f.read()
coor = re.search('(?s)ATOM.*TER', content)
print coor;
这将匹配所有内容 - 包括换行符 - 与 .*
。
请注意,如果您只需要介于两者之间的任何内容(ATOM
包括在内,TER
不包括在内),只需更改为 TER
的积极前瞻:
'(?s)ATOM.*(?=TER)'
【讨论】:
【参考方案3】: import re
pattern=re.compile(r"ATOM(.*?)TER")
print pattern.findall(string)
应该这样做。
【讨论】:
没有分组。而且 findall 效果更好,因为它提供了所有实例。【参考方案4】:我不会使用正则表达式,而是使用 itertool 的 dropwhile
和 takewhile
,这比将整个文件加载到内存中执行正则表达式操作更有效。 (例如,我们只是忽略文件的开头直到 ATOM,然后我们不需要在遇到 TER 后进一步从文件中读取)。
from itertools import dropwhile, takewhile
with open('example.pdb') as fin:
until_atom = dropwhile(lambda L: not L.startswith('ATOM'), fin)
atoms = takewhile(lambda L: L.startswith('ATOM'), until_atom)
for atom in atoms:
print atom,
所以这会忽略不以 ATOM 开头的行,然后在它们仍以 ATOM 开头时继续从该点获取行。如果需要,您可以将该条件更改为 lambda L: not L.startswith('TER')
。
您可以使用以下命令代替打印:
all_atom_text = ''.join(atoms)
获取一个大文本块。
【讨论】:
好点。当我处理大量文件时,我需要比较速度。谢谢。【参考方案5】:非正则表达式替代方案怎么样。它可以通过一个相对简单的循环和一点点状态来实现。示例:
# Gather all sets of ATOM-TER in all_coors (if there are multiple per file).
all_coors = []
f = open('example.pdb', 'w+')
coor = None
in_atom = False
for line in f:
if not in_atom and line.startswith('ATOM'):
# Found first ATOM, start collecting results.
in_atom = True
coor = []
elif in_atom and line.startswith('TER'):
# Found TER, stop collecting results.
in_atom = False
# Save collected results.
all_coors.append(''.join(coor))
coor = None
if in_atom:
# Collect ATOM result.
coor.append(line)
【讨论】:
我使用了非常相似的东西,逐行读取,如果行以 ATOM 开头,直到它以 TER 开头。我认为正则表达式的代码看起来更干净。但我也认为它会比 for 循环更快。 (我没有检查)以上是关于在格式化的文本文件中查找文本块的主要内容,如果未能解决你的问题,请参考以下文章
在文本文件中查找具有特定值的所有行并将它们显示在 datagridview