Почему мое регулярное выражение работает в X, а не в Y?

77

Я написал регулярное выражение, которое хорошо работает в определенной программе (grep, sed, awk, perl, python, ruby, ksh, bash, zsh, find, emacs, vi, vim, gedit,…). Но когда я использую его в другой программе (или в другом варианте Unix), он перестает совпадать. Почему?

Жиль "ТАК - перестань быть злым"
источник

Ответы:

103

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

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

  • +?|(){}требуется ли операторам обратный слеш;
  • какие расширения поддерживаются помимо базовых .[]*^$и обычно+?|()

В этом ответе я перечислю основные стандарты . Проверьте документацию инструментов, которые вы используете для деталей.

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

Основные регулярные выражения (BRE)

Основные регулярные выражения кодифицированы стандартом POSIX . Это синтаксис , используемый grep, sedи vi. Этот синтаксис предоставляет следующие функции:

  • ^и $совпадать только в начале и конце строки.
  • . соответствует любому символу (или любому символу кроме новой строки).
  • […]соответствует любому одному символу, указанному в скобках (набор символов). Если первый символ после открывающей скобки является a ^, символы, которые не перечислены, вместо этого сопоставляются. Чтобы включить ], поместите его сразу после открытия [(или после, [^если это отрицательный набор). Если -между двумя символами, он обозначает диапазон; чтобы включить литерал -, поместите его там, где он не может быть проанализирован как диапазон.
  • Обратная косая черта перед любой из ^$.*\[кавычек следующего символа.
  • * соответствует предыдущему символу или подвыражению 0, 1 или более раз.
  • \(…\)является синтаксической группой, для использования с *оператором или обратными ссылками и \DIGITзаменами.
  • Обратные \1, \2... соответствует точный текст , совпадающий по соответствующей группе, например , \(fo*\)\(ba*\)\1матчи , foobaafooно не foobaafo. Не существует стандартного способа обращения к 10-й группе и далее (стандартное значение \10- первая группа, за которой следует a 0).

Следующие функции также являются стандартными, но отсутствуют в некоторых ограниченных реализациях:

  • \{m,n\}соответствует предыдущему символу или подвыражению от m до n раз; n или m могут быть опущены, и означает точно m .\{m\}
  • Внутри скобок можно использовать классы символов , например, для [[:alpha:]]совпадения с любой буквой. Современные реализации выражений в скобках ) также включают в себя сопоставление элементов like [.ll.]и классов эквивалентности like [=a=].

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

  • \|для чередования: foo\|barсовпадения fooили bar.
  • \?(сокращение от \{0,1\}) и \+(сокращение от \{1,\}) соответствуют предыдущему символу или подвыражению не более 1 раза или не менее 1 раза соответственно.
  • \nсоответствует новой строке, \tсоответствует вкладке и т. д.
  • \wсоответствует любому компоненту слова (сокращенно, [_[:alnum:]]но с изменением, когда дело доходит до локализации) и \Wсоответствует любому символу, который не является компонентом слова.
  • \<и \>сопоставлять пустую строку только в начале или конце слова соответственно; \bсоответствует либо, и \Bсоответствует, где \bнет.

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

Расширенные регулярные выражения (ERE)

Расширенные регулярные выражения кодифицированы стандартом POSIX . Их главное преимущество перед BRE - регулярность: все стандартные операторы - это символы пунктуации, обратная косая черта перед знаком препинания всегда в кавычках. Это синтаксис , используемый awk, grep -Eили egrep, GNU sed -r, и Bash=~ - оператор. Этот синтаксис предоставляет следующие функции:

  • ^и $совпадать только в начале и конце строки.
  • . соответствует любому символу (или любому символу кроме новой строки).
  • […]соответствует любому одному символу, указанному в скобках (набор символов). Дополнение с начальным ^и диапазоном работает как в BRE (см. Выше). Символьные классы могут использоваться, но отсутствуют в нескольких реализациях. Современные реализации также поддерживают классы эквивалентности и элементы сопоставления. Обратная косая черта в скобках заключает в кавычки следующий символ в некоторых, но не во всех реализациях; использовать \\для обозначения обратной косой черты для переносимости.
  • (…)является синтаксической группой, для использования *или \DIGITзамены.
  • |для чередования: foo|barсовпадения fooили bar.
  • *, +И ?соответствует предыдущему символу или подвыражения несколько раз: 0 или более для *, 1 или более для +0 или 1 для ?.
  • Обратная косая черта заключает в кавычки следующий символ, если он не алфавитно-цифровой.
  • {m,n}соответствует предыдущему символу или подвыражению между m и n разами (отсутствует в некоторых реализациях); n или m могут быть опущены, и означает точно m .{m}
  • Некоторые распространенные расширения, как в BRE: обратные ссылки (особенно отсутствуют в awk, за исключением реализации busybox, где вы можете использовать ); специальные символы , и т.д .; границы слова и , составляющие слова и ,…\DIGIT$0 ~ "(...)\\1"\n\t\b\B\b\B

PCRE (Perl-совместимые регулярные выражения)

PCRE - это расширения ERE, изначально представленные Perl и принятые GNU, grep -Pи многие современные инструменты и языки программирования , обычно через библиотеку PCRE . Смотрите документацию Perl для хорошего форматирования с примерами. PCRE поддерживает не все функции последней версии Perl (например, выполнение кода Perl поддерживается только в Perl). См. Руководство по PCRE для получения краткого описания поддерживаемых функций. Основными дополнениями к ERE являются:

  • (?:…)является не захватывающей группой: нравится (…), но не учитывает обратные ссылки.
  • (?=FOO)BAR(lookahead) совпадения BAR, но только если есть совпадение для FOOстарта в той же позиции. Это наиболее полезно для привязки совпадения без включения в него следующего текста: foo(?=bar)совпадения, fooно только если за ним следует bar.
  • (?!FOO)BAR(отрицательный взгляд) совпадает BAR, но FOOв той же позиции также нет совпадения . Например, (?!foo)[a-z]+соответствует любому строчному слову, которое не начинается с foo; [a-z]+(?![0-9)соответствует любому слову в нижнем регистре, за которым не следует цифра (поэтому foo123оно совпадает, foно не совпадает foo).
  • (?<=FOO)BAR(lookbehind) совпадает BAR, но только если ему непосредственно предшествует совпадение для FOO. FOOдолжен иметь известную длину (вы не можете использовать операторы повторения, такие как *). Это наиболее полезно для привязки совпадения без включения предыдущего текста в совпадение: (?<=^| )fooсовпадения, fooно только если ему предшествует пробел или начало строки.
  • (?<!FOO)BAR(отрицательный взгляд сзади) совпадает BAR, но только если ему не предшествует совпадение с FOO. FOOдолжен иметь известную длину (вы не можете использовать операторы повторения, такие как *). Это наиболее полезно для привязки совпадения без включения предыдущего текста в совпадение: (?<![a-z])fooсовпадения, fooно только если ему не предшествует строчная буква.

Emacs

Синтаксис Emacs является промежуточным между BRE и ERE. В дополнение к Emacs, это синтаксис по умолчанию для -regexпоиска в GNU. Emacs предлагает следующие операторы:

Shell шариков

Глобусы оболочки (подстановочные знаки) выполняют сопоставление с шаблоном с использованием синтаксиса, который полностью отличается от регулярных выражений и менее эффективен. В дополнение к оболочкам эти подстановочные знаки доступны с другими инструментами, такими как find -nameи фильтры rsync. Шаблоны POSIX включают в себя следующие функции:

  • ? соответствует любому отдельному символу.
  • […]является набором символов как в общих синтаксисах регулярного выражения. Некоторые оболочки не поддерживают классы персонажей. Некоторые оболочки требуют !вместо того, ^чтобы отрицать множество.
  • *соответствует любой последовательности символов (часто за исключением случаев, /когда сопоставляются пути к файлам; если /исключен из *, то **иногда включает /, но проверяет документацию инструмента).
  • Обратная косая черта указывает на следующий символ.

Ksh предлагает дополнительные функции, которые дают его шаблону полную мощность регулярных выражений. Эти функции также доступны в bash после запуска shopt -s extglob. Zsh имеет другой синтаксис, но может также поддерживать синтаксис ksh после setopt ksh_glob.

Жиль "ТАК - перестань быть злым"
источник
Другие богатые RE, о которых вы, возможно, захотите упомянуть, - vimэто и AT & T libast (как в ksh93).
Стефан Шазелас
@ StéphaneChazelas Кроме vim, какая программа использует регулярные выражения vim? Какая программа, кроме ksh, использует libast?
Жиль "ТАК - перестань быть злым"
все набор инструментов AT & T использует AT & T (УЭ grep, tw, expr...). За исключением того ksh, что этот набор инструментов редко находится за пределами AT & T, хотя.
Стефан Шазелас
Согласно моему пониманию (и Википедии), ваш термин «класс символов» фактически относится к «классу символов POSIX» ... однако, regex(7)соглашается с вами и называет [these]«скобочные выражения» и (в рамках «скобочных выражений») [:these:]«классы символов». Я не уверен, как лучше решить эту проблему.
Адам Кац
Как бы вы их ни называли, они поддерживают диапазоны. Стоит отметить, что он -указывает диапазон и должен быть либо экранирован, либо первым (после необязательного ^), либо последним, если его следует понимать буквально. (Я видел много ошибок , обусловленных , например , [A-z]-ПРИМЕЧАНИЕ изменения в прецедентной, который соответствует символы кодов 65 до 122 и случайно включает в себя каждый из: [\]^_`. Я также видел , действительный еще запутанным , [!-~]чтобы соответствовать все печатаемые символы в ANSI который я предпочитаю видеть как [\x21-\x7e], который по крайней мере прост в своих действиях, хотя и запутывает в другом измерении.)
Адам Кац