Все эти ответы, утверждающие, что вы не можете использовать шаблоны для сопоставления строки со сбалансированными вложенными паренами, совершенно неверны.Не практично делать вид, что шаблоны, соответствующие современным языкам программирования, ограничены «обычными языками» в смысле патологического учебника.Как только вы разрешите обратные ссылки, это не так.Это позволяет реальным шаблонам соответствовать гораздо больше, чем версиям учебников, делая их гораздо более практичными.
Самый простой шаблон для сопоставления сбалансированных паренов - \((?:[^()]*+|(?0))*\)
.Но вы никогда не должны писать это , потому что оно слишком компактно, чтобы его можно было легко прочитать.Вы должны всегда записывать его в режиме /x
для учета пробелов и комментариев.Поэтому напишите это так:
m{
\( # literal open paren
(?: # begin alternation group
[^()]*+ # match nonparens possessively
| # or else
(?0) # recursively match entire pattern
)* # repeat alternation group
\) # literal close paren
}x
Также есть, что сказать, чтобы назвать свои абстракции и отделить их определение и упорядочение от их выполнения.Это приводит к такого рода вещам:
my $nested_paren_rx = qr{
(?&nested_parens)
(?(DEFINE)
(?<open> \( )
(?<close> \) )
(?<nonparens> [^()] )
(?<nested_parens>
(?&open)
(?:
(?&nonparens) *+
|
(?&nested_parens)
) *
(?&close)
)
)
}x;
Вторая форма теперь доступна для включения в более крупные шаблоны.
Никогда не позволяйте никому говорить, что вы не можете использовать шаблон длясопоставить то, что определено рекурсивно.Как я только что продемонстрировал, вы наверняка можете.
Пока вы занимаетесь этим, убедитесь, что никогда не пишете паттерны линейного шума.Вам не нужно, и вы не должны.Нельзя поддерживать язык программирования, который запрещает пробелы, комментарии, подпрограммы или буквенно-цифровые идентификаторы.Поэтому используйте все эти вещи в своих шаблонах.
Конечно, это помогает помочь выбрать правильный язык для такого рода работы.☺