在格式化文本文件中查找文本块

时间:2014-08-08 13:34:05

标签: python regex text-formatting

我经常使用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

但它什么都不匹配。必须有一种方法可以使用正则表达式来获取整个文本块。我也不明白为什么这个正则表达式模式不起作用。感谢帮助。

5 个答案:

答案 0 :(得分:3)

这应该匹配(但我还没有实际测试过):

coor = re.search('ATOM.*TER', content, re.DOTALL)

如果您阅读documentation on DOTALL,就会理解为什么它不起作用。

编写上述内容的更好方法是

coor = re.search(r'^ATOM.*^TER', content, re.MULTILINE | re.DOTALL)

要求ATOMTER位于换行符之后,并且raw string notation正在使用,这是正则表达式的惯例(尽管它不会成功在这种情况下的差异)。

你也可以完全避免使用正则表达式:

start = content.index('\nATOM')
end = content.index('\nTER', start)
coor = content[start:end]

(这实际上不包括结果中的TER,这可能更好。)

答案 1 :(得分:1)

您需要(?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)'

答案 2 :(得分:1)

     import re
     pattern=re.compile(r"ATOM(.*?)TER")
     print pattern.findall(string)

这应该这样做。

答案 3 :(得分:1)

非正则表达式替代方案怎么样?它可以通过一个相对简单的循环和一点点状态来实现。例如:

# 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)

答案 4 :(得分:1)

我不会使用正则表达式,而是使用itertool的dropwhiletakewhile,这比将整个文件加载到内存中以执行正则表达式操作更有效。 (例如,我们只是在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)

获取一个大文本块。