我有一堆文本文件,格式都一样(这是下面的一个片段,真实文件更长):
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
Run Code Online (Sandbox Code Playgroud)
我必须提取所有这些变量并处理它们。我打算编写一些代码,一次遍历每一行,并通过一系列 split、strip 等函数提取相关信息。
这是人们用 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}"""
Run Code Online (Sandbox Code Playgroud)
然后,要按照上述格式从另一个输入文件中提取变量,您将执行以下操作:
list_of_vars = Parse(template, infile)
Run Code Online (Sandbox Code Playgroud)
请注意,虽然相同的变量将出现在每个文件的同一行中,但它们可以向右移动几个字符,具体取决于同一行中它前面的值有多大。
这些文件是 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\) {} {}"""
Run Code Online (Sandbox Code Playgroud)
ParseString 函数成功返回一个字符串列表,然后我可以处理它。由于文件的格式始终相同,因此我能够成功处理所有文件。我只有两个问题。
1) 正如你在上面看到的,我已经在我的模板文件中转义了所有的正则表达式字符,这没什么大不了的。
2) 正如我上面也提到的,这个模板只是我需要解析的实际文件的一小部分。当我用我的真实数据尝试这个时,重新抛出以下错误:
"sorry, but this version only supports 100 named groups" AssertionError: sorry, but this version only supports 100 named groups
Run Code Online (Sandbox Code Playgroud)
我通过将模板字符串拆分为 3 个部分来解决此问题,使用 3 个不同的模板运行 ParseString 函数 3 次,并将列表结果添加到一起。
再次感谢!
这是一个艰难的开始
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')]
Run Code Online (Sandbox Code Playgroud)
如您所见,这会从文件中提取前 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']
Run Code Online (Sandbox Code Playgroud)
这可能已经足够好了