В Perl лексический анализ (лексинг) и парсинг строк часто используются для обработки сложных текстовых шаблонов. Многие задачи (например, разбор вложенных скобок, кавычек, SQL-запросов) не поддаются простым регулярным выражениям из-за их линейной природы. В таких случаях используют модули, реализующие основы парсинга — например, Text::Balanced.
Text::Balanced предназначен для извлечения сбалансированных скобок, парных кавычек и других вложенных структур. Он работает там, где регулярные выражения бессильны (например, парсинг вложенных конструкций { ... { ... } ... }). Среди альтернатив — модули Parse::RecDescent, собственный код на основе стека и рекурсии, а также сторонние парсеры.
Пример использования Text::Balanced и сравнения с regexp:
use Text::Balanced 'extract_bracketed'; my $data = 'foo({bar(baz)},qux)'; my ($extracted, $remainder) = extract_bracketed($data, '()'); print $extracted; # Выведет: ({bar(baz)},qux)
Регулярное выражение не сможет правильно разобрать вложенные скобки:
$data =~ /(\(.*\))/; # захватит лишь первую и последнюю скобку, игнорируя вложенность
Возможно ли на обычных Perl-регулярных выражениях корректно выделить сбалансированные скобки в строках произвольной вложенности?
Ответ: Нет, Perl-регулярные выражения не умеют работать с рекурсивными шаблонами (кроме PCRE, но не стандартного Perl). Для подобной задачи нужно использовать парсер (Text::Balanced, парсер на стеке, Parse::RecDescent). Попытка решить задачу регуляркой приведёт к ошибкам при вложенном синтаксисе.
Пример:
# НЕ сработает для foo({bar(baz)},qux) my ($br) = $data =~ /(\(.*\))/;
История
В проекте были попытки парсить JSON вручную регулярными выражениями. Разработчик рассчитывал, что выражение
(\{.*\})найдёт нужный фрагмент, но на реальных данных с вложенными объектами парсер выбирал неверную границу, что привело к потере данных и ошибкам в обработке входных параметров.
История
В логе XML событий потребовалось вычленять содержимое тэга с потенциальными вложенными тегами. Недостаточное понимание принципов рекурсии в лексинге привело к неверному разбору событий и игнорированию вложенных элементов — часть информации терялась.
История
Ошибка при парсинге SQL-запроса скриптом миграции: исключительные случаи вроде подзапросов в круглых скобках разобрать не получилось. Регулярные выражения "ломались" уже на уровне простых вложенных строк, в результате чего были сформированы некорректные SQL-запросы.