#python #regex #bioinformatics
#python #регулярное выражение #биоинформатика
Вопрос:
Я пытаюсь написать регулярное выражение на python для анализа дерева Newick, но, хоть убей, я не могу привести его последнюю часть в соответствие. Мне нужно проанализировать три типа форматов Newick:
((A,B),C);
((A:0.1,B:0.2),C:0.3);
((A:[c1]0.1,B:[c2]0.2),C:[c2]0.3);
… каждый из которых содержит три метки (A, B, C) и различные другие биты информации. Я хочу получить три метки. Вот мое регулярное выражение:
regex = re.compile(r"""
(
([,(]) # boundary
([A-Z0-9_-.] ) # label
(:)? # optional colon
([. ?])? # optional comment chunk
(d .d )? # optional branchlengths
([),]) # end!
)
""", re.IGNORECASE re.VERBOSE re.DOTALL)
… тем не менее, я получаю только A и C. Никогда B. Я отследил сбой до последней захваченной группы ([),]) — если я удалю это, я получу все A, B и C. Пожалуйста, помогите — что здесь не так ?!
Ответ №1:
Проблема, вероятно, в том, что вы ищете неперекрывающиеся экземпляры регулярного выражения. Такие методы, как findall
не будут возвращать B, поскольку совпадение для A потребляет ,
предыдущее B
.
>>> regex.findall("((A:[c1]0.1,B:[c2]0.2),C:[c2]0.3);")
[('(A:[c1]0.1,', '(', 'A', ':', '[c1]', '0.1', ','), (',C:[c2]0.3)', ',', 'C', ':', '[c2]', '0.3', ')')]
Изменение конечного шаблона для просмотра вперед (чтобы он ничего не потреблял) решает проблему.
>>> regex = re.compile(r"""
... (
... ([,(]) # boundary
... ([A-Z0-9_-.] ) # label
... (:)? # optional colon
... ([. ?])? # optional comment chunk
... (d .d )? # optional branchlengths
... (?=[),]) # end!
... )
... """, re.IGNORECASE re.VERBOSE re.DOTALL)
>>>
>>> regex.findall("((A:[c1]0.1,B:[c2]0.2),C:[c2]0.3);")
[('(A:[c1]0.1', '(', 'A', ':', '[c1]', '0.1'), (',B:[c2]0.2', ',', 'B', ':', '[c2]', '0.2'), (',C:[c2]0.3', ',', 'C', ':
', '[c2]', '0.3')]
>>>
В противном случае, вместо использования findall
, вы можете использовать search
итеративно и обезьянничать с pos
аргументом.
Что-то вроде этого:
>>> x = "((A:[c1]0.1,B:[c2]0.2),C:[c2]0.3);"
>>> r = []
>>> index = 0
>>> while True:
... m = regex.search(x, index)
... if not m:
... break
... r.append(m.groups())
... index = m.end(7)-1
...
>>> r
[('(A:[c1]0.1,', '(', 'A', ':', '[c1]', '0.1', ','), (',B:[c2]0.2)', ',', 'B', ':', '[c2]', '0.2', ')'), (',C:[c2]0.3)',
',', 'C', ':', '[c2]', '0.3', ')')]
Ответ №2:
Если вам просто нужны метки, не могли бы вы просто использовать простое регулярное выражение, например [(,]([A-Z])
?
import re
text = ["((A,B),C);",
"((A:0.1,B:0.2),C:0.3);",
"((A:[c1]0.1,B:[c2]0.2),C:[c2]0.3);"]
for line in text:
labels = re.findall(r'[(,]([A-Z])', line)
print labels
Результат:
['A', 'B', 'C'] ['A', 'B', 'C'] ['A', 'B', 'C']
Комментарии:
1. Я хочу получить весь фрагмент (от начальной границы до конечной границы) и одновременно разобрать его на эти подразделы (начало, метка, комментарий, длины ветвей, конец).