2015-09-23 4 views
0

Я пытаюсь сопоставить несколько блоков последовательных похожих строк, используя регулярное выражение. Точнее, я пытаюсь соответствовать несколько блоков в файле какСогласование нескольких строк с Python

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

Что дает результаты, которые я хочу, однако, я не знаю длину блока, мне нужно, чтобы соответствовать заранее. Как я могу исправить свое регулярное выражение для соответствия нескольким последовательным строкам?

+2

Итак, проблема с вашим вторым примером, который, кажется, работает, заключается в том, что у вас есть список кортежей, а не только один кортеж? Какой выход вы хотите? –

+0

Я хочу сопоставить несколько экземпляров блока, и, таким образом, список кортежей не говорит мне, какие кортежи должны быть в каком блоке. Таким образом, мне понравился список из нескольких кортежей, каждый кортеж, соответствующий блоку. –

ответ

1

Проблема, с которой вы сталкиваетесь, заключается в том, что модуль re Python не обрабатывает повторяющиеся группы. Если у вас есть шаблон, такой как "(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 будет списком списков кортежей, соответствующих блокам и строкам внутри них.

Другой способ решить эту проблему - использовать библиотеку регулярных выражений fancier. У меня не было никакого личного опыта, но я слышал, что regex module позволяет вам повторять группы и получать все полученные результаты. Я действительно не знаю, как это работает, поэтому, если вы идете по этому маршруту, вам придется немного почитать документы или экспериментировать.

Смежные вопросы