Книга: Программирование на языке Ruby
3.13.7. Рекурсия в регулярных выражениях
3.13.7. Рекурсия в регулярных выражениях
Возможность повторно обращаться к подвыражению позволяет создавать рекурсивные регулярные выражения. Например, данный код находит любое вложенное выражение с правильно расставленными скобками (спасибо Эндрю Джексону):
str = "а * ((b-c)/(d-e) - f) * g"
reg = /(? # Начало именованного выражения.
( # Открывающая круглая скобка.
(?: # Незапоминаемая группа.
(?> # Сопоставление с собственническим выражением:
[()] # экранированная скобка
| # ЛИБО
[^()] # вообще не скобка. )
) # Конец собственнического выражения.
| # ЛИБО
g # Вложенная группа в скобках (рекурсивный вызов).
)* # Незапоминаемая группа повторяется нуль или
# более раз.
) # Закрывающая круглая скобка.
) # Конец именованного выражения.
/x
m = reg.match(str).to_a # ["((b-c)/(d-e) - f)", "((b-c)/(d-e) - f)"]
Отметим, что левосторонняя рекурсия запрещена. Следующий пример допустим:
str = "bbbaccc"
re1 = /(?<foo>a|bg<foo>c)/
re1.match(str).to_a # ["bbbaccc","bbbaccc"]
А такой — нет:
re2 = /(?<foo>a|g<foo>c)/ # Синтаксическая ошибка!
Ошибка объясняется наличием рекурсивного обращения в начале каждой альтернативы. Немного подумав, вы поймете, что это приведет к бесконечному возврату.