Spec-Zone.ru › Elisp

Проблемы с регулярными выражениями

Реализация регулярных выражений в Emacs, как и многие подобные реализации, в целом надёжна, но иногда вызывает проблемы двух типов: при сопоставлении может закончиться внутреннее пространство стека и возникнуть ошибка, а само сопоставление может занять много времени. Следующие рекомендации помогут снизить вероятность таких проблем и справиться с теми, которые всё же возникнут.

  • Привязывайте регулярные выражения к началу строки, текста или буфера с помощью проверок нулевой ширины (‘^’ и \`). Это позволяет воспользоваться быстрыми путями в реализации и избежать бесполезных попыток сопоставления. Другие проверки нулевой ширины также могут быть полезны, поскольку позволяют быстрее завершить сопоставление неудачей.
  • Вместо альтернатив используйте выражения в квадратных скобках: пишите ‘[ab]’ вместо ‘a\|b’. Помните, что ‘\s-’ и ‘\sw’ в большинстве случаев эквивалентны ‘[[:space:]]’ и ‘[[:word:]]’ соответственно.
  • Поскольку последняя ветвь альтернативы не добавляет точку возврата в стек, рассмотрите возможность поместить последней наиболее вероятный шаблон. Например, при попытке сопоставить очень длинную строку из символов ‘a’ выражение ‘^\(?:a\|.b\)*c’ исчерпает стек, а эквивалентное ему ‘^\(?:.b\|a\)*c’ — нет.

    (Это компромисс: успешно сопоставленные альтернативы выполняются быстрее, если наиболее часто сопоставляемый шаблон указан первым.)

  • Старайтесь, чтобы каждый фрагмент текста мог сопоставляться только одним способом. Например, ‘a*a*’ будет сопоставляться с тем же набором строк, что и ‘a*’, но первое выражение может делать это множеством способов и поэтому приведёт к медленному возврату, если последующее сопоставление завершится неудачей. По возможности делайте ветви альтернатив взаимоисключающими, чтобы при неудаче сопоставление не продвигалось далеко более чем по одной ветви.

    Будьте особенно осторожны с вложенными повторами: при наличии неоднозначностей они легко приводят к очень медленному сопоставлению. Например, выражение ‘\(?:a*b*\)+c’ будет долго пытаться сопоставить даже умеренно длинную строку из символов ‘a’, прежде чем завершится неудачей. Эквивалентное выражение ‘\(?:a\|b\)*c’ работает гораздо быстрее, а ‘[ab]*c’ — ещё быстрее.

  • Не используйте захватывающие группы, если они действительно не нужны; то есть для группировки используйте ‘\(?:…\)’ вместо ‘\(…\)’.
  • Рассмотрите возможность использования rx (см. Структурная нотация регулярных выражений rx); она может автоматически оптимизировать некоторые альтернативы и никогда не вводит захватывающие группы, если они явно не запрошены.

Если, несмотря на следование приведённым рекомендациям, вы столкнулись с переполнением стека при обработке регулярного выражения, не бойтесь выполнять сопоставление в нескольких вызовах функций, каждый из которых использует более простое регулярное выражение, где возвратом легче управлять.

Функция: re--describe-compiled regexp &optional raw

Чтобы помочь диагностировать проблемы в регулярных выражениях или в самом механизме регулярных выражений, эта функция возвращает строку с описанием скомпилированной формы regexp. Чтобы понять это описание, может потребоваться прочитать как минимум описание типа re_opcode_t в файле src/regex-emacs.c в исходном коде Emacs.

В настоящее время функция может выдавать осмысленное описание, только если Emacs был собран с --enable-checking.

Copyright © 1990-1996, 1998-2026 Free Software Foundation, Inc.
Licensed under the GNU GPL license.
https://www.gnu.org/software/emacs/manual/html_node/elisp/Regexp-Problems.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API