Какие специальные символы должны быть экранированы в регулярных выражениях?

389

Я устал от попыток угадать, следует ли мне избегать специальных символов, таких как ' ()[]{}|' и т. Д., При использовании многих реализаций регулярных выражений.

Он отличается, например, Python, sed, grep, awk, Perl, переименованием, Apache, find и так далее. Существует ли какой-либо набор правил, который сообщает, когда мне следует, а когда нет, экранировать специальные символы? Зависит ли это от типа регулярного выражения, такого как PCRE, POSIX или расширенное регулярное выражение?

Игорь Катсон
источник
4
Хорошие библиотеки регулярных выражений имеют функции типа " escape()", позволяющие использовать произвольные строки в качестве частей регулярных выражений.
ivan_pozdeev
2
Вы можете использовать онлайн-выражения Regex, такие как gskinner.com/RegExr (это бесплатно). (Введите, а затем наведите указатель мыши на регулярное выражение, которое вы ввели)
helicle
2
Избегайте всех не алфавитно-цифровых символов. период.
Салман фон Аббас
2
Этот вопрос был добавлен в FAQ по регулярному выражению переполнения стека в разделе «Другое».
aliteralmind
1
Этот вопрос был добавлен в FAQ по регулярному выражению переполнения стека в разделе «Escape-последовательности».
aliteralmind

Ответы:

365

То, какие персонажи вам нужны, а какие вы не должны избегать, зависит от того, с каким регулярным выражением вы работаете.

Для PCRE и большинства других так называемых Perl-совместимых разновидностей избегайте следующих внешних классов символов:

.^$*+?()[{\|

и эти внутри классов персонажей:

^-]\

Для расширенных регулярных выражений POSIX (ERE) экранируйте эти внешние классы символов (так же, как PCRE):

.^$*+?()[{\|

Экранирование любых других символов - ошибка в POSIX ERE.

Внутри символьных классов обратная косая черта является буквальным символом в регулярных выражениях POSIX. Вы не можете использовать это, чтобы избежать чего-либо. Вы должны использовать «умное размещение», если хотите включить метасимволы классов символов в качестве литералов. Поместите ^ где угодно, кроме как в начале,] в начале и - в начале или в конце класса символов, чтобы они соответствовали буквально, например:

[]^-]

В базовых регулярных выражениях POSIX (BRE) это метасимволы, которые необходимо экранировать, чтобы исключить их значение:

.^$*[\

Исключение скобок и фигурных скобок в BRE придает им особое значение, которое их версии без экранирования имеют в ERE. Некоторые реализации (например, GNU) также дают особое значение другим символам при экранировании, например \? и +. Экранирование символа, отличного от. ^ $ * () {}, Обычно является ошибкой для BRE.

Внутри классов персонажей BRE следуют тем же правилам, что и ERE.

Если все это заставляет вашу голову кружиться , возьмите копию RegexBuddy . На вкладке «Создать» нажмите «Вставить маркер», а затем «Литерал». RegexBuddy будет добавлять экранирование по мере необходимости.

Ян Гойваертс
источник
1
Мне кажется, вы забыли "/", который также должен быть экранирован вне класса.
Джекхипстер
11
/не является метасимволом ни в одном из упомянутых мною вариантов регулярного выражения, поэтому синтаксис регулярного выражения не требует его экранирования. Когда регулярное выражение цитируется как литерал на языке программирования, то строка или регулярных выражений форматирования правила этого языка может потребовать /или "или 'быть экранированы, и может даже потребовать `\` , чтобы быть вдвойне убежали.
Ян Гойваертс
2
как насчет двоеточия, ":"? Должен ли он быть экранирован как внутри классов персонажей, так и снаружи? ru.wikipedia.org/wiki/Perl_Compatible_Regular_Expressions говорит, что «PCRE имеет последовательные экранирующие правила: любой не алфавитно-цифровой символ может быть экранирован, чтобы обозначать его буквальное значение [...]»
nicolallias
4
МОЖЕТ быть спасено не то же самое, что ДОЛЖНО быть спасено. Синтаксис PCRE никогда не требует экранирования буквального двоеточия, поэтому экранирование буквальных двоеточий только затрудняет чтение вашего регулярного выражения.
Ян Гойваертс
1
Для не POSIX ERE (который я использую чаще всего потому, что это реализовано в Tcl) экранирование других вещей не приводит к ошибкам.
Slebetman
61

Modern RegEx Flavors (PCRE)

Включает в себя C, C ++, Delphi, EditPad, Java, JavaScript, Perl, PHP (preg), PostgreSQL, PowerGREP, PowerShell, Python, REALbasic, Real Studio, Ruby, TCL, VB.Net, VBScript, wxWidgets, XML-схему, Xojo, XRegExp.
PCRE совместимость может отличаться

    Где угодно: . ^ $ * + - ? ( ) [ ] { } \ |


Legacy RegEx Flavors (BRE / ERE)

Включает в себя awk, ed, egrep, emacs, GNUlib, grep, PHP (ereg), MySQL, Oracle, R, sed.
Поддержка PCRE может быть включена в более поздних версиях или с использованием расширений

ERE / AWK / задать расширенное / Emacs

    Вне класса персонажа: . ^ $ * + ? ( ) [ { } \ |
    Внутри класса персонажа:^ - [ ]

BRE / Под ред / Grep / СЭД

    За пределами класса символов: . ^ $ * [ \
    Внутри класса символов: ^ - [ ]
    Для литералов не экранировать: + ? ( ) { } |
    Для стандартного поведения регулярных выражений экранировать:\+ \? \( \) \{ \} \|


Ноты

  • Если вы не уверены в конкретном символе, его можно экранировать как \xFF
  • Буквенно-цифровые символы не могут быть экранированы обратной косой чертой
  • Произвольные символы могут быть экранированы с помощью обратной косой черты в PCRE, но не BRE / ERE (они должны экранироваться только при необходимости). Для PCRE] - нужно только экранировать внутри класса символов, но я сохранил их в одном списке для простоты
  • В строках выражения в кавычках также должны быть экранированные символы кавычек, и часто с удвоенными обратными слешами (например, "(\")(/)(\\.)" , по сравнению /(")(\/)(\.)/с JavaScript)
  • Помимо выходов, различные реализации регулярных выражений могут поддерживать разные модификаторы, классы символов, якоря, квантификаторы и другие функции. Для получения более подробной информации, посетите регулярно-expressions.info , или используйте regex101.com, чтобы проверить свои выражения вживую
Beejor
источник
1
В вашем ответе много ошибок, включая, но не ограничиваясь: ни один из ваших «современных» вариантов не требует -и не ]должен выходить за пределы классов символов. POSIX (BRE / ERE) не имеет escape-символа внутри классов символов. Аромат регулярных выражений в RTL Delphi фактически основан на PCRE. Python, Ruby и XML имеют свои собственные разновидности, которые ближе к PCRE, чем к POSIX.
Ян Гойваертс
1
@JanGoyvaerts Спасибо за исправление. Упоминаемые вами ароматы действительно ближе к PCRE. Что касается побегов, я сохранил их так для простоты; легче вспомнить просто убежать везде, чем несколько исключений. Опытные пользователи будут знать, что случилось, если они хотят избежать нескольких обратных слешей. Во всяком случае, я обновил свой ответ с несколькими разъяснениями, которые, надеюсь, касаются некоторых из этих вещей.
Beejor
22

К сожалению, на самом деле нет набора управляющих кодов, поскольку он зависит от используемого вами языка.

Однако сохранение такой страницы, как страница « Инструменты регулярных выражений» или эта таблица регулярных выражений, может помочь вам быстро отфильтровать вещи.

Dillie-О
источник
1
Шпаргалка Addedbytes сильно упрощена и содержит некоторые явные ошибки. Например, он говорит \<и \>представляет собой границы слов, что является истинным только (AFAIK) в библиотеке регулярных выражений Boost. Но в другом месте он говорит , <и >являются метасимволы и должны быть экранированы (к \<и \>) , чтобы соответствовать их в буквальном смысле, что не так в любой вкус
Алан Мур
5

К сожалению, значение таких вещей, как (и \ (поменялись местами между регулярными выражениями в стиле Emacs и большинством других стилей). Поэтому, если вы попытаетесь избежать их, вы можете делать то, что вам нужно.

Таким образом, вы действительно должны знать, какой стиль вы пытаетесь процитировать.

Darron
источник
5

POSIX распознает множество вариаций регулярных выражений - базовые регулярные выражения (BRE) и расширенные регулярные выражения (ERE). И даже тогда есть причуды из-за исторических реализаций утилит, стандартизированных POSIX.

Не существует простого правила, когда использовать какую нотацию или даже какую нотацию использует данная команда.

Ознакомьтесь с книгой Джеффа Фридла « Освоение регулярных выражений» .

Джонатан Леффлер
источник
4

На самом деле нет. существует около полумиллиона различных синтаксисов регулярных выражений; похоже, они относятся к Perl, EMACS / GNU и AT & T в целом, но я всегда удивляюсь.

Чарли Мартин
источник
4

Иногда простое экранирование невозможно с указанными вами персонажами. Например, использование обратной косой черты для экранирования скобки не будет работать в левой части строки подстановки в sed, а именно

sed -e 's/foo\(bar/something_else/'

Вместо этого я просто использую простое определение класса символов, поэтому приведенное выше выражение становится

sed -e 's/foo[(]bar/something_else/'

который я считаю работами для большинства реализаций регулярных выражений.

КСТАТИ Символьные классы - это довольно ванильные компоненты регулярных выражений, поэтому они, как правило, работают в большинстве ситуаций, когда вам нужно экранировать символы в регулярных выражениях.

Изменить: После комментария ниже, просто подумал, что я бы упомянул тот факт, что вы также должны учитывать разницу между автоматами с конечным состоянием и автоматами с конечным состоянием при рассмотрении поведения оценки регулярного выражения.

Возможно, вы захотите взглянуть на «блестящую книгу», также называемую Effective Perl ( очищенная ссылка Amazon ), в частности главу о регулярных выражениях, чтобы почувствовать разницу в типах оценки движка регулярных выражений.

Не весь мир PCRE!

В любом случае, регулярные выражения настолько неуклюжи по сравнению со СНОБОЛОМ ! Теперь , что был интересный курс программирования! Вместе с тем на Симуле .

Ах, радости учебы в UNSW в конце 70-х! (-:

Роб Уэллс
источник
'sed' - это команда, для которой обычный '(' не является особенным, но '\ (' является особенным; напротив, PCRE меняет смысл, поэтому '(' является особенным, но '\ (' - нет. Это именно то, что ОП спрашивает о
Джонатан Леффлер
sed - это утилита * nix, которая использует один из самых примитивных наборов оценки регулярных выражений. PCRE не входит в ситуацию, которую я описываю, так как он включает в себя другой класс (не) конечных автоматов с тем, как он оценивает регулярные выражения. Я думаю, что мое предложение для минимального набора синтаксиса регулярных выражений все еще остается в силе.
Роб Уэллс
1
В POSIX-совместимой системе sed использует POSIX BRE, о чем я расскажу в своем ответе. Версия GNU в современной системе Linux использует POSIX BRE с несколькими расширениями.
Ян Гойваертс
2

Для PHP «всегда безопаснее предшествовать не алфавитно-цифровому символу« \ », чтобы указать, что оно обозначает себя». - http://php.net/manual/en/regexp.reference.escape.php .

За исключением случаев, когда это "или".: /

Чтобы избежать переменных шаблона регулярных выражений (или частичных переменных) в PHP, используйте preg_quote ()

zylstra
источник
2

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

Помните, как обрабатывается строка в памяти: если это может быть простая строка внутри кода или строка, введенная в командную строку, но может быть либо интерактивной командной строкой, либо командной строкой, указанной в файле сценария оболочки, или внутри переменной в памяти, упомянутой кодом, или (строковым) аргументом при дальнейшей оценке, или строкой, содержащей код, сгенерированный динамически с любой инкапсуляцией ...

Каждому из этого контекста назначено несколько символов со специальным функционалом.

Если вы хотите передать символ буквально, не используя его специальную функцию (локальную для контекста), тогда вам нужно его экранировать для следующего контекста ... который может потребовать некоторых других escape-символов, которые могут потребоваться дополнительно сбежал в предыдущем контексте (ах). Кроме того, могут быть такие вещи, как кодировка символов (наиболее коварным является utf-8, потому что он выглядит как ASCII для общих символов, но может дополнительно интерпретироваться даже терминалом в зависимости от его настроек, поэтому он может вести себя по-другому, чем атрибут кодирования HTML / XML, необходимо правильно понимать процесс.

Например, регулярное выражение в командной строке, начинающееся с perl -npe, должно быть передано в набор системных вызовов exec, соединяющихся как канал, который обрабатывает файл, каждый из этих системных вызовов exec просто имеет список аргументов, которые были разделены пробелами (не являющимися экранированными), и, возможно, трубы (|) и перенаправление (> N> N> & M), скобки, интерактивное расширение *и? ,$(())... (все это специальные символы, используемые * sh, которые могут показаться мешающими символу регулярного выражения в следующем контексте, но они оцениваются по порядку: перед командной строкой. Командная строка читается запрограммируйте как bash / sh / csh / tcsh / zsh, по сути, внутри двойной кавычки или одинарной кавычки, экранирование проще, но нет необходимости заключать в кавычки строку в командной строке, потому что в большинстве случаев пробел должен начинаться с обратной косой черты, а кавычка необязательно оставлять доступной функциональность раскрытия для символов * и?, но этот синтаксический анализ отличается от контекста, как в кавычке. Затем при оценке командной строки регулярное выражение, полученное в памяти (а не записанное в командной строке), получает ту же обработку, что и будет в исходном файле. Для регулярного выражения есть контекст набора символов в квадратных скобках [],Регулярное выражение perl может быть заключено в большой набор не алфавитно-цифровых символов (например, m // или m: / better / for / path: ...).

У вас есть больше деталей о символах в другом ответе, которые очень специфичны для конечного контекста регулярного выражения. Как я уже отмечал, вы упоминаете, что вы находите escape-выражение с попытками, возможно, потому, что другой контекст имеет другой набор символов, который запутал вашу память о попытках (часто обратный слеш - это символ, используемый в этом другом контексте для экранирования литерального символа вместо его функции. ).

Марко Мунари
источник
0

Для Ionic (Typescript) вы должны удвоить косую черту, чтобы выделить символы. Например (это соответствует некоторым специальным символам):

"^(?=.*[\\]\\[!¡\'=ªº\\-\\_ç@#$%^&*(),;\\.?\":{}|<>\+\\/])"

Обратите внимание на этих ] [ - _ . /персонажей. Они должны быть дважды разрезаны. Если вы этого не сделаете, в вашем коде будет ошибка типа.

Алехандро дель Рио
источник