Регулярные выражения
Практические регулярные выражения появились в ранних версиях Unix и использовались в редакторе ed. Обычно регулярные выражения ассоциируются с утилитой grep (Global search for Regular Expressions and Print lines).
Содержание
Зачем они нужны?
ОболочкаShell практически не имеет никаких встроенных средств обработки текста, кроме самых примитивных; эта задача перекладывается на внешние программы. Регулярные выражения (regular expressions) — мощный и эффективный инструмент обработки текста, совместно с возможностями оболочки позволяет конструировать простые и компактные инструменты.
Где используются
Регулярные выражения используются в таких программах, как sed (ЯзыкSed, потоковый редактор), grep (поиск текста по шаблону), awk (ЯзыкAWK, язык для обработки текстов и отчётов) и многих других. Существует две разновидности (стиля) регулярных выражений; они отличны друг от друга, и в то же время имело место взаимопроникновение. В настоящее время POSIX специфицирует BRE (basic regular expressions — базовые регулярные выражения) и ERE (extended regular expressions — расширенные регулярные выражения). Синтаксис BRE поддерживается большинством утилит Unix.
Шаблоны на основе регулярных выражений
Для демонстрации примеров регулярных выражений будет использоваться утилита grep. Это удобный способ интерактивной отладки и проверки регулярных выражений.
$ echo 'Billy and Jimmy' | grep 'Jimmy' Billy and Jimmy $
Если регулярное выражение совпадает со строкой, то grep печатает её на терминал. Определить было ли совпадение со строкой можно и по коду возврата grep так:
$ echo 'Mikhail Bulgakov' | grep 'Mikhail' >/dev/null && echo 'OK' OK $
Предыдущий пример подавляет вывод grep средствами оболочки (перенаправление в /dev/null), в то же время POSIX предлагает опцию -q для этой цели.
$ echo 'Leo Tolstoy' | grep -q 'Tolstoy' && echo 'OK' OK $
Привязка выражений к началу и концу строки
Регулярное выражение дает совпадение со строкой в том случае,
если искомый образец содержится в любом месте строки.
Символы «ˆ» и «$»,
используемые для привязки совпадения к началу и концу строки,
называют якорями.
Например, регулярное выражение apple
совпадает со строкой myapples
,
но ˆapple$
даст совпадение только со строкой apple
.
В то же время регулярное выражение ˆapple
даст совпадение с applesaregood
,
а apple$
совпадёт со строкой redapple
.
$ echo myapples | grep 'apple' myapples $ echo apple | grep '^apple$' apple $ echo badapple | grep '^apple$' $ echo applesaregood | grep '^apple' applesaregood $ echo redapple | grep 'apple$' redapple $
В регулярных выражениях символ «ˆ» имеет два значения.
Встретившись в самом начале выражения он работает как якорь,
привязывая образец к началу строки;
выражение ˆ[a-z]
совпадает с любой строкой,
начинающейся со строчной буквы латинского алфавита.
Следуя после открывающей квадратной скобки ([) символ «ˆ» инвертирует группу символов;
выражение [ˆa-z]
совпадает с любой строкой,
не содержащей строчных букв латинского алфавита.
$ echo aqua | grep '[a-z]' aqua $ echo aqua | grep '[^a-z]' $ echo 1qua | grep '[^a-z]' 1qua $ echo 'a3ua' | grep '^[a-z]' a3ua $ echo '9qua' | grep '^[a-z]' $
Оператор «*», атомы и подвыражения
В регулярных выражениях
в отличие от шаблонов оболочки оператор «*» не даёт совпадения сам по себе,
а изменяет поведение предыдущего символа.
Регулярное выражение cat*
даст совпадение со строками ca
, cat
и catxyz
.
$ echo ca | grep 'cat*' ca $ echo cat | grep 'cat*' cat $ echo catxyz | grep 'cat*' catxyz $
Точка (.) совпадает с любым одиночным символом,
а «*» изменяет его поведение так,
что выражение даёт совпадение с любой последовательностью символов,
в том числе и с пустой строкой.
Оператор «*» действует,
если быть точным,
не на предыдущий символ,
а на элементарную конструкцию называемую атомом (atom).
Любой одиночный символ является атомом.
Атом можно получить из любого выражения, заключив его в \(…\).
Например, регулярное выражение ma\(ma\)*
совпадает со строками ma
,
mama
, mamama
,
но не совпадает с mam
.
$ echo 'ma' | grep 'ma\(ma\)*' ma $ echo 'mama' | grep 'ma\(ma\)*' mama $ echo 'mamama' | grep 'ma\(ma\)*' mamama $ echo mam | grep 'ma\(ma\)*' $
Любое выражение, заключённое в \(…\), называется подвыражением (subexpression). Подвыражения могут быть вложенными на любую глубину.
Обратные ссылки
В регулярном выражении может присутствовать обратная ссылка (back-reference) на строку
(возможно, пустую) совпавшую с подвыражением.
Такую ссылку вставляют на порядковый номер подвыражения (от 1 до 9).
Нумерация подвыражений начинается с единицы (\1
, \2
и т. д.),
а подсчёт ведётся по открывающей \(
.
Например, регулярное выражение \([0-9]\)\1
совпадёт со строками 00
, 33
и т. д. —
с любой строкой, содержащей две одинаковых цифры.
$ echo 00 | grep '\([0-9]\)\1' 00 $ echo 33 | grep '\([0-9]\)\1' 33 $ echo 59 | grep '\([0-9]\)\1' $
На вложенные подвыражения тоже можно ссылаться.
Так регулярное выражение \([0-9]\([a-z]\)\)\1\2
совпадает со строками 0a0aa
, 1b1bb
,
но со строкой 1a0aa
совпадения уже нет.
$ echo 0a0aa | grep '\([0-9]\([a-z]\)\)\1\2' 0a0aa $ echo 1b1bb | grep '\([0-9]\([a-z]\)\)\1\2' 1b1bb $ echo 1a0aa | grep '\([0-9]\([a-z]\)\)\1\2' $
Следует добавить, что обратные ссылки тоже являются атомами. Кроме оператора «*» в регулярных выражениях существует возможность уточнить количество и/или диапазон совпадений атома операторами \{x\} — точно x совпадений, \{x,\} — минимум x совпадений и \{x,y\} — от x совпадений до y совпадений включительно), где 0 ≤ x ≤ y.
Например, примитивную проверку IP-адреса можно осуществить следующим образом:
$ echo 192.255.255.255 | grep '^\([0-9]\{3\}\.\)\{3\}[0-9]\{3\}$' 192.255.255.255 $ echo 1.2.3 | grep '^\([0-9]\{3\}\.\)\{3\}[0-9]\{3\}$' $
Расширенные регулярные выражения (ERE)
Расширенные регулярные выражения обычно ассоциируются с egrep (или grep -E
).
В отличие от базовых регулярных выражений,
в ERE для группировки и в операторах повтора не используются обратные слэши,
по этой причине они читаются и записываются проще.
Например, предыдущий пример с проверкой IP-адреса записывается в ERE так:
$ echo 192.255.255.255 | grep -E '^([0-9]{3}\.){3}[0-9]{3}$' 192.255.255.255 $
Ещё одним отличием от BRE является наличие оператора «ИЛИ» (читается как «OR»).
Регулярное выражение orange|apple
совпадает и со строкой apple
и со строкой orange
.
$ echo apple | grep -E 'orange|apple' apple $ echo orange | grep -E 'orange|apple' orange $
Оператор «|» имеет низкий приоритет,
поэтому регулярное выражение a|bc
совпадает с a
или
bc
, но не с ac
и bc
.
$ echo a | grep -E 'a|bc' a $ echo bc | grep -E 'a|bc' bc $ echo ac | grep -E 'a|bc $ echo bc | grep -E 'a|bc' $
Чтобы получить совпадение с ac
и bc
нужно поставить скобки: (a|b)c
.
$ echo ac | grep -E '(a|b)c' ac $ echo bc | grep -E '(a|b)c' bc $
Обратные ссылки в ERE отсутствуют (в некоторых реализациях они есть как расширение).
Считается, что обратные ссылки могут приводить к весьма неэффективным по
производительности конструкциям;
они избыточны в синтаксисе регулярных выражений и в
большинстве случаев можно обойтись без них.
Для удобства в ERE добавлены ещё два оператора повторения «?» и «+».
Оператор «?» равнозначен {0,1}, а оператор «+» равнозначен {1,}.
Заметим,
что многие реализации BRE тоже «понимают» \+
, \?
и оператор \|
.
Краткое руководство
- c
- Любой неспециальный символ c совпадает сам с собой.
- \c
- Отменить действие специального символа c.
- ˆ
- Привязать выражение к началу строки.
- $
- Привязать выражение к концу строки.
- .
- Совпадает с любым одиночным символом.
- […]
- Совпадает с любым символом из ...; диапазоны задают в виде a-z.
- [ˆ…]
- Совпадает с любым cимволом, кроме указанного в ...; можно задавать диапазон.
- \n
- Строка с которой совпало n-ное подвыражение \(...\), где 0 ≤ n ≤ 9.
- \(…\)
- Превращает … в подвыражение.
- r*
- Совпадает с выражением r ноль или больше раз; совпадает с пустой строкой.
- r\{x\}
- Совпадает с выражением r точно x раз.
- r\{x,\}
- Совпадает с выражением r от x раз и больше.
- r\{x,y\}
- Совпадает с выражением r от x раз до y раз (включительно).
- r1 r2
- Конкатенация (объединение) выражений r1 и r2.
Литература
- 1 The Open Group Base Specifications Issue 7 [Электронный ресурс]
- Regular Expressions / The IEEE and The Open Group. — IEEE Std 1003.1, 2013 Edition. — 2013. — Режим доступа: http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap09.html, свободный.
КатегорияЯзыкиПрограммирования