Ответ 1
Все эти ответы, утверждая, что вы не можете использовать шаблоны для соответствия строкам со сбалансированными вложенными парадами, совершенно неправильны. Нецелесообразно притворяться, что шаблоны, согласованные с современными языками программирования, ограничены "регулярными языками" в смысле патологического учебника. Как только вы разрешаете обратные ссылки, это не так. Это позволяет модели реального мира соответствовать гораздо большему, чем версии учебников, что делает их гораздо более практичными.
Самый простой шаблон для сопоставления сбалансированных парендов - \((?:[^()]*+|(?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;
Вторая форма теперь подлежит включению в более крупные шаблоны.
Никогда не позволяйте никому говорить, что вы не можете использовать шаблон для соответствия тому, что рекурсивно определено. Как я только что продемонстрировал, вы, безусловно, можете.
Пока вы на нем, убедитесь, что никогда не записываете шаблоны линейного шума. Вам это не нужно, и вы не должны. Нельзя поддерживать язык программирования, который запрещает использование пробелов, комментариев, подпрограмм или буквенно-цифровых идентификаторов. Поэтому используйте все эти вещи в своих шаблонах.
Конечно, это помогает выбрать правильный язык для такого рода работ. ☺