我试图使用正则表达式匹配连续相似行的多个块。确切地说,我试图匹配文件中的多个块,如
H 0 0 0
O 0 0 1
H 0 1 1
在文件中出现多次,具有不同的值(对于那些好奇的人,我试图通过量子化学几何优化程序获取分子几何输出)。
我尝试了像
这样的正则表达式import re
# atom x y z
>>> my_re = r'(\s*(\w+)\s+(\d+)\s+(\d+)\s+(\d+)\n)+'
>>> my_string = 'lorem ipsum\nH 0 0 0\nO 0 0 1\nH 0 1 1\nlorem ipsum'
>>> re.findall(my_re, my_string)
[('H 0 1 1\n', 'H', '0', '1', '1')]
它不匹配整个分子块,而只匹配块的最后一行。如果我删除最后的+
,那么正则表达式会单独匹配块的所有行,即
[('H 0 0 0\n', 'H', '0', '0', '0'),
('O 0 0 1\n', 'O', '0', '0', '1'),
('H 0 1 1\n', 'H', '0', '1', '1')]
如果我复制它,我的正则表达式很乐意匹配连续的行,例如
>>> re.findall(my_re*3, a)
[('H 0 0 0\n', 'H', '0', '0', '0',
'O 0 0 1\n', 'O', '0', '0', '1',
'H 0 1 1\n', 'H', '0', '1', '1')]
这给出了我想要的结果,但是,我不知道我需要提前匹配的块的长度。如何修复我的正则表达式以匹配多个连续的行?
答案 0 :(得分:1)
您遇到的问题是Python的re
模块无法很好地处理重复的群组。如果您的模式类似"(foo)+"
且匹配"foofoofoo"
,则模式将匹配整个字符串,但只会捕获最后一个"foo"
子字符串。
有几种方法可以解决这个问题。我的第一个想法是在没有任何捕获组的情况下进行第一次匹配传递,以便将整个块作为字符串获取,然后在每个块上重新匹配(使用捕获组)以解析各行中的值:
block_re = r'(?:\s*\w+\s+\d+\s+\d+\s+\d+\n)+' # no groups, findall will yield strings
row_re = r'(\s*(\w+)\s+(\d+)\s+(\d+)\s+(\d+))' # you may not want the outer group here
results = [re.findall(row_re, block) for block in re.findall(block_re, my_string)]
results
变量将是元组列表的列表,对应于块及其中的行。
另一种解决方法是使用更高级的正则表达式库。我没有任何亲身经历,但我听说regex
module允许你重复小组并仍然可以获得所有捕获的结果。我实际上并不知道它是如何工作的,所以如果你走这条路,你将不得不阅读文档或进行一些实验。