Проблемы с регулярными выражениями
Реализация регулярных выражений в 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