基于python中的模板文件从文件中解析信息

时间:2017-09-26 15:29:03

标签: python regex

我有一堆文本文件,都是相同的格式(下面是一个片段,真实文件更长):

Molecular weight = 43057.32         Residues = 391   
Average Residue Weight  = 110.121   Charge   = -10.0
Isoelectric Point = 4.8926

Residue     Number      Mole%       DayhoffStat
A = Ala     24      6.138       0.714   
B = Asx     0       0.000       0.000   
C = Cys     9       2.302       0.794   

Property    Residues        Number      Mole%
Tiny        (A+C+G+S+T)     135     34.527
Small       (A+B+C+D+G+N+P+S+T+V)   222     56.777
Aliphatic   (A+I+L+V)       97      24.808

我必须提取所有这些变量并处理它们。我打算编写一些代码,每次执行一行,并通过一系列拆分,剥离等函数提取相关信息。

这是人们用python做的一个非常常见的任务,所以我认为必须有一个更简单的方法。

是否有任何模块或方法允许以下内容:

template = """
Molecular weight = {0}          Residues = {1}   
Average Residue Weight  = {2}   Charge   = {3}
Isoelectric Point = {4}

Residue     Number      Mole%       DayhoffStat
A = Ala     {4}     {5}         {6}
B = Asx     {7}     {8}         {9}     
C = Cys     {10}    {11}        {12}    

Property    Residues        Number      Mole%
Tiny        (A+C+G+S+T)     {14}        {15}
Small       (A+B+C+D+G+N+P+S+T+V)   {16}        {17}
Aliphatic   (A+I+L+V)       {18}        {19}"""

然后,要按照上述格式从另一个输入文件中提取变量,您将执行以下操作:

list_of_vars = Parse(template, infile)

请注意,虽然相同的变量将出现在同一行的每个文件中,但它们可以向右移动几个字符,具体取决于同一行上它前面的值有多大。

文件是emboss pepstats的输出,以防有人想知道。

感谢大家的快速回复。这里的解决方案是在re模块中使用findall函数。以下是一个简单的示例:

import re

class TemplateParser:
    def __init__(self, template):
        self.m_template = template.replace('{}', r'[\s]*([\d\-\.]+)[\s]*')

    def ParseString(self, filename):
        return re.findall(self.m_template, filename, re.DOTALL|re.MULTILINE)[0]

template = """
Molecular weight = {}          Residues = {}   
Average Residue Weight  = {}   Charge   = {}
Isoelectric Point = {}

Residue     Number      Mole%       DayhoffStat
A = Ala     {}    {}        {}
B = Asx     {}    {}        {}     
C = Cys     {}    {}        {}    

Property    Residues        Number      Mole%
Tiny        \(A\+C\+G\+S\+T\)     {}        {}
Small       \(A\+B\+C\+D\+G\+N\+P\+S\+T\+V\)   {}        {}
Aliphatic   \(A\+I\+L\+V\)       {}        {}"""

ParseString函数成功返回一个字符串列表,然后我可以处理它。由于文件总是相同的格式,我能够成功处理我的所有文件。我只有两个问题。

1)正如你在上面所看到的那样,我已经在我的模板文件中逃脱了所有正则表达式字符,这并不是什么大不了的事。

2)正如我上面提到的,这个模板只是我需要解析的实际文件的一小部分。当我用我的真实数据尝试这个时,重新抛出以下错误:

"sorry, but this version only supports 100 named groups" AssertionError: sorry, but this version only supports 100 named groups

我通过将模板字符串分成3个部分来解决这个问题,使用3个不同的模板运行ParseString函数3次,并将列表结果一起添加。

再次感谢!

2 个答案:

答案 0 :(得分:1)

这是一个艰难的开始

In [3]: data = """Molecular weight = 43057.32         Residues = 391   
   ...: Average Residue Weight  = 110.121   Charge   = -10.0
   ...: Isoelectric Point = 4.8926
   ...: 
   ...: Residue     Number      Mole%       DayhoffStat
   ...: A = Ala     24      6.138       0.714   
   ...: B = Asx     0       0.000       0.000   
   ...: C = Cys     9       2.302       0.794   
   ...: 
   ...: Property    Residues        Number      Mole%
   ...: Tiny        (A+C+G+S+T)     135     34.527
   ...: Small       (A+B+C+D+G+N+P+S+T+V)   222     56.777
   ...: Aliphatic   (A+I+L+V)       97      24.808
   ...: """
In [5]: rx=r'Molecular weight += +([0-9\.]+).*Residues += +([0-9]+).*Average Residue Weight += +([0-9\.]+).*Charge += +([-+]*[0-9\.]+)'
     rx=r'Molecular weight += +([0-9\.]+).*Residues += +([0-9]+).*Average Residue Weight += +([0-9\.]+).*Charge += +([-+]*[0-9\.]+)'
In [7]: import re
In [12]: re.findall(rx, data, re.DOTALL|re.MULTILINE)
Out[12]: [('43057.32', '391', '110.121', '-10.0')]

如您所见,这将从文件中提取前4个字段。如果您确实拥有这样的固定格式文件,则可以扩展正则表达式以在一次调用中获取所有数据。

你需要修改子表达式以获得正确的浮点格式等 - 正如我所说,这是一个快速的概念验证。如果真实文件明显更大,RE可能会变得非常冗长或难以调试。

仅供比较,以下是使用ctwheels在评论中提供的正则表达式获取相同数据的内容

In [13]: rx2='(?:\s*([a-zA-Z()+ ]+?)[ =]*)([-+]?\d+\.?\d*)'

In [14]: re.findall(rx2,data)
Out[14]: 
[('Molecular weight', '43057.32'),
 ('Residues', '391'),
 ('Average Residue Weight', '110.121'),
 ('Charge', '-10.0'),
 ('Isoelectric Point', '4.8926'),
 ('Ala', '24'),
 (' ', '6.138'),
 (' ', '0.714'),
 ('Asx', '0'),
 (' ', '0.000'),
 (' ', '0.000'),
 ('Cys', '9'),
 (' ', '2.302'),
 (' ', '0.794'),
 ('Tiny        (A+C+G+S+T)', '135'),
 (' ', '34.527'),
 ('Small       (A+B+C+D+G+N+P+S+T+V)', '222'),
 (' ', '56.777'),
 ('Aliphatic   (A+I+L+V)', '97'),
 (' ', '24.808')]
In [15]: [m[1] for m in _]
Out[15]: 
['43057.32',
 '391',
 '110.121',
 '-10.0',
 '4.8926',
 '24',
 '6.138',
 '0.714',
 '0',
 '0.000',
 '0.000',
 '9',
 '2.302',
 '0.794',
 '135',
 '34.527',
 '222',
 '56.777',
 '97',
 '24.808']

哪个可能够好

答案 1 :(得分:1)

我可以看到此线程早已得到答复,但与OP具有相同的想法-使用模板解析文本数据-最终创建了模板文本解析器模块:https://ttp.readthedocs.io/en/latest/

示例python代码来解析OP的文本:

template = """
<group>
Molecular weight = {{ Molecular_weight }}         Residues = {{ Residues }}   
Average Residue Weight  = {{ Average_Residue_Weight }}   Charge   = {{ Charge }}
Isoelectric Point = {{ Isoelectric_Point }}

<group name="table1">
## Residue              Number                Mole%       DayhoffStat
{{ Residue | PHRASE }}  {{ Number | DIGIT }}  {{ Mole }}  {{ DayhoffStat }}
</group>

<group name="table2">
## Property     Residues        Number                Mole%
{{ Property }}  {{ Residues }}  {{ Number | DIGIT }}  {{ Mole }}
</group>
</group>
"""

sample_data = """
Molecular weight = 43057.32         Residues = 391   
Average Residue Weight  = 110.121   Charge   = -10.0
Isoelectric Point = 4.8926

Residue     Number      Mole%       DayhoffStat
A = Ala     24      6.138       0.714   
B = Asx     0       0.000       0.000   
C = Cys     9       2.302       0.794   

Property    Residues        Number      Mole%
Tiny        (A+C+G+S+T)     135     34.527
Small       (A+B+C+D+G+N+P+S+T+V)   222     56.777
Aliphatic   (A+I+L+V)       97      24.808
"""

from ttp import ttp
parser = ttp(sample_data, template)
result = parser.result(format="pprint")
print(result[0])

会产生:

[   {   'Average_Residue_Weight': '110.121',
        'Charge': '-10.0',
        'Isoelectric_Point': '4.8926',
        'Molecular_weight': '43057.32',
        'Residues': '391',
        'table1': [   {   'DayhoffStat': '0.714',
                          'Mole': '6.138',
                          'Number': '24',
                          'Residue': 'A = Ala'},
                      {   'DayhoffStat': '0.000',
                          'Mole': '0.000',
                          'Number': '0',
                          'Residue': 'B = Asx'},
                      {   'DayhoffStat': '0.794',
                          'Mole': '2.302',
                          'Number': '9',
                          'Residue': 'C = Cys'}],
        'table2': [   {   'Mole': '34.527',
                          'Number': '135',
                          'Property': 'Tiny',
                          'Residues': '(A+C+G+S+T)'},
                      {   'Mole': '56.777',
                          'Number': '222',
                          'Property': 'Small',
                          'Residues': '(A+B+C+D+G+N+P+S+T+V)'},
                      {   'Mole': '24.808',
                          'Number': '97',
                          'Property': 'Aliphatic',
                          'Residues': '(A+I+L+V)'}]}]