Какие специальные символы должны быть экранированы в регулярных выражениях?
Я устал от попыток угадать, стоит ли мне избегать специальных символов, таких как '()[]{}|
и т. д. при использовании многих реализаций регулярных выражений.
Он отличается, например, Python, sed, grep, awk, Perl, переименованием, Apache, find и так далее. Существует ли какой-либо набор правил, который сообщает, когда мне следует, а когда нет, экранировать специальные символы? Зависит ли это от типа регулярного выражения, такого как PCRE, POSIX или расширенное регулярное выражение?
14 ответов
То, какие персонажи вам нужны, а какие вы не должны избегать, зависит от того, с каким регулярным выражением вы работаете.
Для PCRE и большинства других так называемых Perl-совместимых разновидностей избегайте следующих внешних классов символов:
.^$*+?()[{\|
и эти внутри классов персонажей:
^-]\
Для расширенных регулярных выражений POSIX (ERE) экранируйте эти внешние символьные классы (так же, как PCRE):
.^$*+?()[{\|
Экранирование любых других символов - ошибка с POSIX ERE.
Внутри символьных классов обратная косая черта является буквальным символом в регулярных выражениях POSIX. Вы не можете использовать это, чтобы избежать чего-либо. Вы должны использовать "умное размещение", если хотите включить метасимволы классов символов в качестве литералов. Поместите ^ где угодно, кроме как в начале,] в начале и - в начале или в конце класса символов, чтобы они соответствовали буквально, например:
[]^-]
В базовых регулярных выражениях POSIX (BRE) это метасимволы, которые необходимо экранировать, чтобы исключить их значение:
.^$*
Исключение скобок и фигурных скобок в BRE придает им особое значение, которое их версии без экранирования имеют в ERE. Некоторые реализации (например, GNU) также дают особое значение другим символам при экранировании, например \? и +. Экранирование символа, отличного от.^$*(){}, Обычно является ошибкой для BRE.
Внутри классов персонажей BRE следуют тем же правилам, что и ERE.
Если все это заставляет вашу голову кружиться, возьмите копию RegexBuddy. На вкладке "Создать" нажмите "Вставить маркер", а затем "Литерал". RegexBuddy будет добавлять побег по мере необходимости.
Современные 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, или используйте https://regex101.com/, чтобы проверить свои выражения вживую
К сожалению, на самом деле не существует набора управляющих кодов, поскольку он зависит от используемого вами языка.
Однако сохранение такой страницы, как страница " Инструменты регулярных выражений" или эта таблица регулярных выражений, может помочь вам быстро отфильтровать вещи.
POSIX распознает множество вариаций регулярных выражений - базовые регулярные выражения (BRE) и расширенные регулярные выражения (ERE). И даже тогда есть причуды из-за исторических реализаций утилит, стандартизированных POSIX.
Не существует простого правила, когда использовать какую нотацию или даже какую нотацию использует данная команда.
Ознакомьтесь с книгой Джеффа Фридла " Освоение регулярных выражений".
На самом деле нет. существует около полумиллиона различных синтаксисов регулярных выражений; похоже, они относятся к Perl, EMACS/GNU и AT&T в целом, но я всегда удивляюсь.
К сожалению, значение таких вещей, как (и \(поменялись местами между регулярными выражениями в стиле Emacs и большинством других стилей). Поэтому, если вы попытаетесь избежать их, вы можете делать то, что вам нужно.
Таким образом, вы действительно должны знать, какой стиль вы пытаетесь процитировать.
https://perldoc.perl.org/perlre.html и https://perldoc.perl.org/functions/quotemeta.html
В официальной документации, цитируя метасимволы:
my $regex = quotemate($string)
s/$regex/something/
Иногда простое экранирование невозможно с указанными вами персонажами. Например, использование обратной косой черты для экранирования скобки не будет работать в левой части строки подстановки в sed, а именно
sed -e 's/foo\(bar/something_else/'
Вместо этого я просто использую простое определение класса символов, поэтому приведенное выше выражение становится
sed -e 's/foo[(]bar/something_else/'
который я считаю работами для большинства реализаций регулярных выражений.
КСТАТИ Символьные классы - это довольно ванильные компоненты регулярных выражений, поэтому они, как правило, работают в большинстве ситуаций, когда вам нужно экранировать символы в регулярных выражениях.
Изменить: После комментария ниже, просто подумал, что я бы упомянул тот факт, что вы также должны учитывать разницу между автоматами с конечным состоянием и автоматами с конечным состоянием при рассмотрении поведения оценки регулярного выражения.
Возможно, вы захотите взглянуть на "блестящую книгу", также называемую Effective Perl ( очищенная ссылка Amazon), в частности на главу о регулярных выражениях, чтобы почувствовать разницу в типах оценки движка регулярных выражений.
Не весь мир PCRE!
В любом случае, регулярные выражения настолько неуклюжи по сравнению со СНОБОЛОМ! Теперь это был интересный курс программирования! Вместе с тем на Симуле.
Ах, радости от учебы в UNSW в конце 70-х! (-:
Для PHP "всегда безопасно предшествовать не алфавитно-цифровому символу"\", чтобы указать, что оно обозначает себя". - http://php.net/manual/en/regexp.reference.escape.php.
За исключением случаев, когда это "или".:/
Чтобы избежать переменных шаблона регулярного выражения (или частичных переменных) в PHP, используйте preg_quote()
Чтобы понять, когда и что избегать без попыток, необходимо точно понимать цепочку контекстов, через которые проходит строка. Вы будете указывать строку от самой дальней стороны до ее конечного пункта назначения, которая является памятью, обработанной кодом синтаксического анализа регулярного выражения.
Помните, как обрабатывается строка в памяти: если это может быть простая строка внутри кода или строка, введенная в командную строку, но может быть либо интерактивной командной строкой, либо командной строкой, указанной в файле сценария оболочки, или внутри переменной в памяти, упомянутой кодом, или (строковым) аргументом при дальнейшей оценке, или строкой, содержащей код, сгенерированный динамически с любой инкапсуляцией...
Каждому из этого контекста назначено несколько символов со специальным функционалом.
Если вы хотите передать символ буквально, не используя его специальную функцию (локальную для контекста), тогда вам нужно его экранировать для следующего контекста... который может потребовать некоторых других escape-символов, которые могут потребоваться дополнительно сбежал в предыдущем контексте (ах). Кроме того, могут быть такие вещи, как кодировка символов (наиболее коварным является utf-8, потому что он выглядит как ASCII для общих символов, но может дополнительно интерпретироваться даже терминалом в зависимости от его настроек, поэтому он может вести себя по-другому, чем атрибут кодирования HTML/XML, необходимо правильно понимать процесс.
Например, регулярное выражение в командной строке, начинающееся с perl -npe
, должен быть передан в набор системных вызовов exec, соединяющихся как канал, который обрабатывает файл, каждый из этих системных вызовов exec просто имеет список аргументов, которые были разделены пробелами (не экранированными), и, возможно, pipe (|) и redirection (> N> N>&M), скобки, интерактивное расширение *
а также ?
, $(())
... (все это специальные символы, используемые * sh, которые могут показаться мешающими символу регулярного выражения в следующем контексте, но они оцениваются по порядку: перед командной строкой. Командная строка читается запрограммируйте как bash/sh/csh/tcsh/zsh, по сути, внутри двойной кавычки или одинарной кавычки, экранирование проще, но нет необходимости заключать в кавычки строку в командной строке, потому что в большинстве случаев пробел должен начинаться с обратной косой черты, а кавычка необязательно оставлять доступной функциональность раскрытия для символов * и?, но этот синтаксический анализ отличается от контекста, как в кавычке. Затем при оценке командной строки регулярное выражение, полученное в памяти (а не записанное в командной строке), получает ту же обработку, что и будет в исходном файле. Для регулярного выражения есть контекст набора символов в квадратных скобках [ ], регулярное выражение perl может быть заключено в кавычки большим набором не альфа-числовых символов (например, m// или m:/better/for/ дорожка: ...).
У вас есть больше деталей о символах в другом ответе, которые очень специфичны для конечного контекста регулярного выражения. Как я уже отмечал, вы упоминаете, что вы находите escape-выражение с попытками, возможно, потому, что другой контекст имеет другой набор символов, который запутал вашу память о попытках (часто обратный слеш - это символ, используемый в этом другом контексте для экранирования литерального символа вместо его функции.).
за
awk
, если вы параноик и хотите сбежать от всего на всякий случай, то это должно помочь:
от
ASCII
безопасный список терминала:
!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ
[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
примените это:
gsub(/[!-/{-~:-@[-\140]/, "[&]")
gsub(/\^|\\/, "\\\\&" )
делать :
[!]["][#][$][%][&]['][(][)][*][+][,][-][.][/]
0123456789[:][;][<][=][>][?]
[@]ABCDEFGHIJKLMNOPQRSTUVWXYZ[[][\\][]][\^][_]
[`]abcdefghijklmnopqrstuvwxyz[{][|][}][~]
Использование Raku (ранее известного как Perl_6)
Работает (обратная косая черта или кавычки всех не буквенно-цифровых символов, кроме подчеркивания):
~$ raku -e 'say $/ if "#.*?" ~~ m/ \# \. \* \? /; #works fine'
「#.*?」
Согласно pdf/talk Дамиана Конвея «Все, что вы знаете о регулярных выражениях, неверно» , существует шесть разновидностей языков регулярных выражений . Raku представляет собой значительную (примерно 15 лет) переработку стандартных регулярных выражений Perl(5)/PCRE.
За эти 15 лет эксперты по языку Perl_6 / Raku решили, что все не буквенно-цифровые символы (кроме подчеркивания) должны быть зарезервированы как метасимволы Regex, даже если в настоящее время их не используют. Чтобы обозначить небуквенно-цифровые символы (кроме подчеркивания) как литералы, используйте обратную косую черту или экранируйте их.
Таким образом, приведенный выше пример печатает$/
переменная match, если совпадение с литералом#.*?
найдена последовательность символов. Ниже показано, что произойдет, если вы этого не сделаете:#
интерпретируется как начало комментария,.
точка интерпретируется как любой символ (включая пробел),*
звездочка интерпретируется как нуль или более квантификатор, и?
вопросительный знак интерпретируется либо как нуль-или-один квантификатор, либо как скромный (т.е. нежадный) квантификатор-модификатор (в зависимости от контекста):
Ошибки:
~$ ~$ raku -e 'say $/ if "#.*?" ~~ m/ # . * ? /; #ERROR!'
===SORRY!===
Regex not terminated.
at -e:1
------> y $/ if "#.*?" ~~ m/ # . * ? /; #ERROR!⏏<EOL>
Regex not terminated.
at -e:1
------> y $/ if "#.*?" ~~ m/ # . * ? /; #ERROR!⏏<EOL>
Couldn't find terminator / (corresponding / was at line 1)
at -e:1
------> y $/ if "#.*?" ~~ m/ # . * ? /; #ERROR!⏏<EOL>
expecting any of:
/
Возможно, старый поток, но этот код может быть полезен посетителям, которые хотят создавать без регулярного выражения
def listToString(s):
# initialize an empty string
str1 = ""
# return string
return (str1.join(s))
r = "Hello! How are you? *Smiling_Face* *Heart* erwer"
r1 = list(r)
i = 0
r2 = list()
start = True
for string in r1:
if string == "*":
if(start):
start = False
else:
start = True
else:
if(start):
r2.append(string)
else:
print("skipped" + string)
print(listToString(r2))
Для Ionic (Typescript) вы должны использовать двойную косую черту, чтобы скрыть символы. Например (это соответствует некоторым специальным символам):
"^(?=.*[\\]\\[!¡\'=ªº\\-\\_ç@#$%^&*(),;\\.?\":{}|<>\+\\/])"
Обратите внимание на это ] [ - _ . /
символы. Они должны быть разрезаны с двух сторон. Если вы этого не сделаете, в вашем коде будет ошибка типа.