使用Python匹配同一行的多个

时间:2015-09-23 20:39:50

标签: python regex

我试图使用正则表达式匹配连续相似行的多个块。确切地说,我试图匹配文件中的多个块,如

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')]

这给出了我想要的结果,但是,我不知道我需要提前匹配的块的长度。如何修复我的正则表达式以匹配多个连续的行?

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允许你重复小组并仍然可以获得所有捕获的结果。我实际上并不知道它是如何工作的,所以如果你走这条路,你将不得不阅读文档或进行一些实验。