Регулярные выражения


Содержание

Учебник: Регулярные выражения (regular expressions)

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

  • Вы пишете программу, в которой обрабатываются номера телефонов, допустим в формате +7(ххх)ххх-хх-хх. Возможно их надо найти в тексте, а может быть — проверить корректность. На месте номеров могли бы быть номер банковской карты, IP-адрес, электронная почта, ФИО (в формате Петров А.Ю.), да и вообще что угодно.
  • В Microsoft Word при поиске и замене можно включить режим поддержки регулярных выражений поставив галочку напротив пункта «подстановочные знаки». Потом можно искать все то, что указано в первом пункте, но программу писать не требуется. И заменять можно. В LibreOffice/OpenOffice это тоже поддерживается.
  • Естественно, регулярные выражения поддерживаются во всех современных средах разработки — Qt Creator, Microsoft Visual Studio, NetBeans, IntelliJ IDEA и даже блокнотах — Notepad++, kate, gedit и др. Вы пишете код и решили что-то переименовать, да как-то особенно…

Остается научиться всем этим пользоваться. Значительную часть описанных ниже примеров можно проверить в том же Notepad++ или Microsoft Word. Для других (связанных с программированием) — можно использовать сервис regex101, он удобен не только для обучения, но и для реальной разработки.

Содержание:

1 Теоретический раздел

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

1.1 Одиночные символы

Символ «точка» (.) заменяет в регулярных выражениях любой символ. Так, например, если в тексте есть слова «порог» и «пирог» — то выражение «п.рог» будет удовлетворять обоим из них. Ниже приведен пример такого поиска в тектовом редакторе kate, остальные примеры будут даваться без скриншотов.

Если же нас интересуют не все варианты замены символа — используется представление с квадратными скобками. В скобках перечисляются альтернативные символы. Также, в квадратных скобках можно задавать диапазоны символов с помощью «тире». Ниже приведена схема для выражения «var_[a-d][123]», можно попробовать выписать строки, которое оно описывает:

Если символ «тире» должен являться частью перечисления — его нужно ставить первым или последним. Например, в таком выражении:

ставить тире между «+» и «*» нельзя, так как это будет интерпретировано как диапазон.

Также с помощью перечислений можно искать «все символы кроме», для этого первым символом перечисления должен быть «^» . Так, чтобы найти в тексте все символы кроме «ё» , «й» и символов «a-z» можно использовать такое выражение: «[^ёйa-z]» .

Если символ «^» стоит вне квадратных скобок — то он задает начало строки (до сих пор поиск осуществлялся во всем тексте). Символ «$» соответствует концу строки.

Если вдруг вам нужно найти в тексте какой-либо из «управляющих символов» — то его нужно экранировать с помощтю слеша. Так, например, символы «^» , «[» в регулярном выражении должны быть заменены на «\^» , «\[» . На практике часто приходится искать символ слеша, который также является управляющим и заменяется на «\\» .

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

Выражение Символ
«\d» цифра
«\D» все кроме цифры «[^0-9]»
«\s» пробельный символ (табуляции, пробелы)
«\S» все, кроме пробельных символов
«\w» буква (любой язык, в любом регистре)
«\W» все кроме букв
«\b» граница слова
«\B» не граница слова

Такие обозначения могут использоваться в качестве элементов перечисления, например «[\d\w]» соответствует букве или цифре.

1.2 Квантификация

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

Выражение Количество повторений
«*» 0 или более раз
«+» 1 или более раз
«?» 0 или 1 раз
«« точно n раз
«« от n до m раз

С помощью кванторов мы можем описать, например строку, содержащую номер банковской карты:

Под такое описание подойдут, например, строки «1234-1234-1234-1234» и «12345678 12345678» .

1.3 группировка (подвыражения)

Выражение может состоять из подвыражений, заключенных в круглые скобки. Для программиста это очень важно, так как к подвыражению можно обратиться по индексу. Кроме того, подвыражения используются для задания альтернатив, которые можно перечислять с помощью вертикальной черты. Так, например, следующее выражение соответствует строкам «+7 902», «8(902)» и еще множеству вариантов:

Тут «\(» используется для экранирования скобок. Подвыражения на практике применяются очень часто, но нам не всегда нужна возможность получить подстроку, соответствующую подвыражению. При выборе подстрок в коде вашей программы «лишние» подвыражения мешают, из-за них «съезжают» индексы, исправить ситуацию можно с использованием следующего синтаксиса: «(?:pattern)» . Кроме того, такая форма записи более эффективна, т.к. сохраняет меньше данных.

Также, с группами связано так называемое «заглядывание вперед» — это нечасто применяемая на практике техника позволяет проверить соответствие подвыражению, не смещая позицию поиска и не запоминая найденное соответствие. Синтаксис используется следующий «(?=pattern)» . Пусть дан следующий файл со списком языков программирования:

мы ожидаемо получим три строки, однако что если, к уже найденному подвыражению требуется применить какие-то дополнительные «фильтры»? То есть, после этой проверки мы хотим еще раз проверить названия языков. Сделать это можно заменив «?:» на «?=» .

Теперь будут получены только две строки — Lua и Lisp, а второе подвыражение «(.*)» будет сопоставлено с типами соответствующих языков.

Негативное заглядывания вперед ищет несоответствие строки шаблону «(?!pattern)» . Такое выражение выбирает подстроки, не соответствующие «pattern» без запоминания подстроки и не смещая текущую позицию поиска. Так, для рассмотренного выше примера, такой тип заглядывания вернет единственную строку с языком Logo. Первое подвыражение выберет строки с языками Basic, Prolog, С++ и Logo, а второе — оставит из них только те, чьи названия начинаются с символа «L» .

1.4 Что есть еще?

Наряду с заглядыванием вперед, в некоторых реализациях поддерживается позитивное и негативное заглядывания назад — «(? и «(? , соответственно. Полезно знать, что нечто подобное существует, чтобы в случае чего — найти в справочнике и применить.

Описанное выше должно одинаково работать в любой среде, поддерживающей регулярные выражения, однако в отдельных реализациях доступно больше возможностей или синтаксис выражений может незначительно отличаться. С помощью регулярных выражений можно искать строки в тексте, однако в каком регистре выполняется поиск? — ответ зависит от реализации. Управлять регистром можно с помощью модификаторов : «(?i)» включает чувствительность к регистру, а «(?-i)» — выключает ее. Существуют и другие модификаторы, но они используются реже. Работа модификаторов зависит от реализации. Некоторые реализации поддерживают также флаги, которыми также можно управлять регистром.

Ряд реализаций поддерживает очень удобный поиск по условию: «(?(?=если)то|иначе)» . Нечто подобное позволяет реализовать «просмотр вперед». «Если» условие выполнится — будет выполнено сопоставление с «то», в противном случае — с «иначе». Сопоставление в данном случае создает группу, к которой можно обратиться по индексу из вашего кода.

2 Практический раздел. Ссылки

Перед тем, как использовать регулярные выражения, стоит посмотреть в документацию по вашему языку программирования и используемой библиотеке, так как диалекты обладают особенностями. Например в Perl и некоторых версиях php можно описывать рекурсивные регулярные выражения, которые не поддерживаются большинством других реализаций; механизмом флагов отличается JavaScript и так далее. Незначительными отличиями могут обладать даже различные версии одной и той же библиотеки.

Отличаются регулярные выражения не только синтаксисом, но и реализацией. Регулярные выражения — это «не просто так». Строка, задающее выражение, преобразуется в автомат, от реализации которого зависит эффективность. Масштаб проблемы хорошо иллюстрирует график зависимости времени выполнения поиска от длины строки и реализации:

Картинка взята из статьи «Поиск с помощью регулярных выражений может быть простым и быстрым«. В ней можно прочитать про различные реализации выражений, а также о том, как написать выражение так, чтобы оно работало быстрее. Кстати, так как выражение преобразуется в автомат, то зачастую его удобно визуализировать — для этого есть специальные сервисы, например. Для последнего выражения статьи будет построен такой автомат:

Примеры использования регулярных выражений:

  • для валидации вводимых в поля данных: QVal >javax.faces.validator.Validator ;
  • для парсинга сайтов: Парсер сайта на Qt, использование QRegExp. В примере с сайта-галереи выбираются и скачиваются картинки заданных категорий;
  • для валидации данных, передаваемых в формате JSON ряд библиотек позволяет задавать схему. При этом для строковых полей могут быть заданы регулярные выражения. В качестве упражнения можно попробовать составить выражение для пароля — проверить что строка содержит символы в разном регистре и цифры.

В сообществе Программирование и алгоритмы можно посмотреть дополнительную литературу по теме. Книгу Гойвертса и Левитана рекомендую посмотреть особенно, так как в ней по-полочкам разобраны десятки примеров, причем с учетом специфики реализации регулярных выражений в конкретных языках программирования.

Регулярные выражения (RegEx)¶

Вступление¶

Регулярные выражения — удобный способ описывать шаблоны текстов.

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

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

Символы¶

Простые совпадения¶

Любой отдельный символ соответствует самому себе.

Серия символов соответствует этой серии символов во входной строке.

RegEx Находит
foobar foobar

Непечатные символы (escape-коды)¶

Для представления непечатаемого символа в регулярном выражении вы используете \x.. :

RegEx Находит
\xnn символ с шестнадцатеричным кодом « nn«
\x символ с шестнадцатеричным кодом nnnn (один байт для простого текста и два байта для Unicode)
foo\x20bar foo bar (обратите внимание на пробел в середине)

Существует ряд предопределенных escape-кодов для непечатных символов, как в языке C :

RegEx Находит
\t tab (HT/TAB), тоже что \x09
\n символ новой строки (NL), то же что \x0a
\r car.return (CR), тоже что \x0d
\f form feed (FF), то же что \x0c
\a звонок (BEL), тоже что \x07
\e escape (ESC), то же что \x1b
\tfoobar foobar , перед которым стоит TAB

Эскейпинг¶

Если вы хотите использовать символ \ сам по себе, а не как часть escape-кода , просто добавьте к нему префикс \ , например: \\ .

На самом деле вы можете поставить перед префиксом (или escape )«« любой символ, имеющий особое значение в регулярных выражениях.

RegEx Находит
\^FooBarPtr ^FooBarPtr здесь ^ не означает начало строки
\[a\] [a] это не класс символов

Классы символов¶

Пользовательские классы¶

Символьный класс — это список символов внутри [] . Класс соответствует любому одному символу, указанному в этом классе.

RegEx Находит
foob[aeiou]r foobar , foober и т. д., но не foobbr , foobcr и т. д.

Вы можете инвертировать класс — если первый символ после [ является ^ , то класс соответствует любому символу, кроме символов, перечисленных в классе.

RegEx Находит
« Foob [^ AEIOU] r« foobbr , foobcr и т. д., но не foobar , foober и т. д.

Внутри списка символ — используется для указания диапазона, так что a-z представляет все символы между a и z включительно.

Если вы хотите, чтобы — сам был членом класса, поместите его в начало или конец списка или escape с обратной косой чертой.

Если вы хотите буквально использовать символы ] или [ , поместите их в начало списка или escape обратной косой чертой.

RegEx Находит
[-az] a , z и —
[az-] a , z и —
[А\-z] a , z и —
[a-z] символы от a до z
[\n-\x0D] символы от #10 до #13

Предопределенные классы символов¶

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

RegEx Находит
\w буквенно-цифровой символ (включая _ )
\W не буквенно-цифровой
\d числовой символ (такой же как [0123456789] )
\D нечисловой
\s любой пробел (такой же как [\t\n\r\f] )
\S не пробел
RegEx Находит
foob\dr foob1r , foob6r и т. д., но не foobar , foobbr и т. д.
foob[\w\s]r foobar , foob r , foobbr и т. д., но не foob1r , foob=r и т. д.

Свойства SpaceChars и WordChars определяют, какие символы входят в классы \w , \W ,«s«, \S .

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

Разделители¶

Разделители строк¶

RegEx Находит
^ начало строки
$ конец строки
\A начало текста
\Z конец текста
. любой символ в строке
^Foobar foobar только если он находится в начале строки
foobar$ foobar , только если он в конце строки
^foobar$ foobar только если это единственная строка в строке
foob.r foobar , foobbr , foob1r и так далее

Метасимвол ^ по умолчанию соответствует началу входной строки. $ — конец.

Однако вы можете захотеть рассматривать строку как многострочный текст, так что ^ будет соответствовать месту перед разделителем строк во входном тексте, а $ — месте после любого разделителя строк. Для этого переключите modifier /m.

Обратите внимание, что в последовательности \x0D\x0A нет пустой строки.

Если вы используете Unicode версию, то ^ / $ также соответствует \x2028 , \x2029 , \x0B , \x0C или \x85 .

\A и \Z похожи на ^ и $ , за исключением того, что они не будут совпадать несколько раз, когда modifier /m используется.

Метасимвол . по умолчанию соответствует любому символу, но если вы переключите Off на modifier /s, то . не будет совпадать с разделителями строк внутри строки.

Обратите внимание, что выражение ^.*$ не соответствует точке между \x0D\x0A , потому что это неразрывный разделитель строк. Но оно соответствует пустой строке в последовательности \x0A\x0D , потому из-за неправильного порядка кодов он не воспринимается как разделитель строк и считается просто двумя символами.

Многострочная обработка может быть настроена с помощью свойств LineSeparators и LinePairedSeparator.

Таким образом, вы можете использовать разделители стиля Unix \n или стиль DOS / Windows \r\n или смешивать их вместе (как описано выше по умолчанию).

Если вы предпочитаете математически правильное описание, вы можете найти его на сайте www.unicode.org.

Разделители слов¶

RegEx Находит
\b разделитель слов
\B разделительс с не-словом

Граница слова \b — это точка между двумя символами, у которой \w с одной стороны от нее и \W с другой стороны (в любом порядке).

Повторы¶

Повтор¶

За любым элементом регулярного выражения может следовать допустимое число повторений элемента.

RegEx Находит
ровно n раз
по крайней мере n раз
по крайней мере n , но не более чем m раз
* ноль или более, аналогично
+ один или несколько, похожие на
? ноль или единица, похожая на

То есть цифры в фигурных скобках определяются минимальное n и максимальное m количество повторов (совпадений во входном тексте).

эквивалентно и означает точно n раз .

соответствует n или более раз.

Нет ограничений на величину n и m .

Если фигурная скобка встречается в любом другом контексте, она рассматривается как обычный символ.

RegEx Находит
foob.*r foobar , foobalkjdflkj9r и foobr
foob.+r foobar , foobalkjdflkj9r , но не foobr
foob.?r foobar , foobbr и foobr , но не foobalkj9r
fooba<2>r foobaar
fooba<2>r foobaar , foobaaar , foobaaaar и т. д.
fooba<2,3>r foobaar , или foobaaar , но не foobaaaar
(foobar) 8 , 9 или 10 экземпляров foobar ( () это Subexpression)

Жадность¶

Повторы в жадном режиме захватывают как можно больше из входного текста, в не жадном режиме — как можно меньше.

По умолчанию все повторы являются жадными . Используйте ? Чтобы сделать любой повтор не жадным .

Для строки abbbbc :

RegEx Находит
b+ bbbb
Ь+? b
b*? пустой строки
b<2,3>? bb
b bbb

Вы можете переключить все квантификаторы в режим не жадный (modifier /g, ниже мы используем in-line модификатор change).

RegEx Находит
(?-g)Ь+ b

Альтернативы¶

Выражения в списке альтернатив разделяются | .

Таким образом, fee|fie|foe будет соответствовать любому из fee , fie или foe (также как и f(e|i|o)e ).

Первое выражение включает в себя все от последнего разделителя шаблона ( ( , [ или начало шаблона) до первого | , а последнее выражение содержит все от последнего | к следующему разделителю шаблона.

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

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

Например, регулярное выражение foo|foot в строке barefoot будет соответствовать foo — первое же совпадение.

Также помните, что | в квадратных скобках воспринимается просто как символ, поэтому, если вы напишите [fee|fie|foe] , это тоже самое что [feio|] .

RegEx Находит
foo(bar|foo) foobar или foofoo

Подвыражения¶

Скобки (. ) также могут использоваться для определения подвыражений регулярного выражения.

Позиция, длина и фактические значения подвыражений будут в MatchPos, MatchLen и Match.

Вы можете заменить их на Заменить.

Подвыражения нумеруются слева направо по открывающим их скобкам (включая вложенные подвыражения).

Первое подвыражение имеет номер 1 . Целое регулярное выражение имеет номер 0 .

Например, для входной строки foobar регулярное выражение (foo(bar)) найдет:

подвыражение значение
foobar
1 foobar
2 bar

Backreferences¶

Метасимволы от \1 до \9 интерпретируются как обратные ссылки. \n соответствует ранее найденному подвыражению n .

RegEx Находит
(.)\1+ aaaa и cc
(.+)\1+ также abab и 123123

([‘»]?)(\d+)\1 соответствует «13» (в двойных кавычках) или ‘4’ (в одинарных кавычках) или 77 (без кавычек) и т. д.

Модификаторы¶

Модификаторы предназначены для изменения поведения регулярных выражений.

Вы можете установить модификаторы глобально в вашей системе или изменить их внутри регулярного выражения, используя (?imsxr-imsxr).

Для изменения модификаторов используйте ModifierStr или соответствующие TRegExpr свойства Модификатор *.

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

i, без учета регистра¶

Регистро-независимые сравнения. Использует установленные в вашей системе языковые настройки, см. также InvertCase.

m, многострочные строки¶

Обрабатывать строку как несколько строк. Таким образом, ^ и $ соответствуют началу или концу любой строки в любом месте строки.

s, одиночные строки¶

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

Смотрите также Разделители строк, которые обычно не совпадают.

г, жадность¶

Специфичный для TRegExpr модификатор.

Отключив его Off , вы переключите повторитель в не-жадный режим.

Итак, если модификатор /g имеет значение Off , то + работает как +? , * как *? и так далее.

По умолчанию этот модификатор имеет значение Выкл .

x, расширенный синтаксис¶

Позволяет комментировать регулярные выражения и разбивать их на несколько строк.

Если модификаторор Вкл , мы игнорируем все пробелы, которые не заэскейплены обратной косой чертой, и не включены в класс символов.

Также символ # отделяет комментарии.

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

Это также означает, что если вам нужно вставить пробел или символ # в шаблон (вне класса символов, где они не затрагиваются /x ), вам придется либо эскейпить их, либо кодировать, используя шестнадцатеричный код.

г, русские диапазоны¶

Специфичный для TRegExpr модификатор.

В русской таблице ASCII символы ё / Ё размещаются отдельно от других.

Большие и маленькие русские символы находятся в отдельных диапазонах, это не отличается от ситуации с английскими символами, но, тем не менее, я хотел иметь краткую форму.

С этим модификатором вместо [а-яА-ЯёЁ] вы можете написать [а-Я] , если вам нужны все русские символы.

Когда модификатор Вкл :

RegEx Находит
а-я символы от а до я и ё
А-Я символы от А до Я и Ё
а-Я все русские символы

Модификатор по умолчанию установлен на Вкл .

Расширения¶

Заглядывание вперед . Проверяет совпадение для регулярного выражения в , но не включает это совпадение в результат.

Заглядывание вперед не реализовано в TRegExpr.

Во многих случаях вы можете заменить Заглядывание вперед на Sub-expression и просто игнорировать то, что будет записано в этом подвыражении.

Например, (blah)(?=аoobar)(blah) совпадает с (blah)(foobar)(blah) . Но в варианте с подвыражениеями вы должны исключить среднее подвыражение вручную — используйте Match [1] + Match [3] и игнорируйте Match[2] .

Это просто не так удобно, как с Заглядыванием вперед , где вы можете использовать весь Match[0] , поскольку захваченное совпадение не будет включено в найденное регулярное выражение.

(?imsgxr-imsgxr)¶

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

Это может быть особенно удобно, поскольку оно имеет локальную область видимости в регулярном выражении. Оно влияет только на ту часть регулярного выражения, которая следует за оператором (?imsgxr-imsgxr) .

И если оно находится внутри подвыражения, оно будет влиять только на это подвыражение, а именно на ту часть подвыражения, которая следует за оператором. Таким образом, в ((?i)Saint)-Petersburg это влияет только на подвыражение ((?i)Saint) , поэтому оно будет соответствовать saint-Petersburg , но не saint-petersburg ,

RegEx Находит
(?i)Saint-Petersburg Saint-petersburg и Saint-Petersburg
(?i)Saint-(?-i)Petersburg Saint-Petersburg , но не Saint-petersburg
(?i)(Saint-)?Petersburg Saint-petersburg и saint-petersburg
((?i)Saint-)?Petersburg saint-Petersburg , но не saint-petersburg

(?#текст)¶

Комментарий, текст игнорируется.

Обратите внимание, что комментарий закрывается ближайшим ) , поэтому нет способа вставить литерал ) в комментарий.

Послесловие¶

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

© Copyright 2020, Andrey Sorokin Revision 2180a345 .

Руководство по регулярным выражениям в JavaScript

Введение в регулярные выражения

Регулярные выражения (RegExp) — это очень эффективный способ работы со строками.

Составив регулярное выражение с помощью специального синтаксиса вы можете:

  • искать текст в строке
  • заменять подстроки в строке
  • извлекать информацию из строки

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

Регулярные выражения относятся к 1950-м годам, когда они были формализованы как концептуальный шаблон поиска для алгоритмов обработки строк.

Регулярные выражения реализованные в UNIX, таких как grep, sed и популярных текстовых редакторах, начали набирать популярность и были добавлены в язык программирования Perl, а позже и в множество других языков.

JavaScript, наряду с Perl, это один из языков программирования в котором поддержка регулярных выражений встроена непосредственно в язык.

Сложно, по полезно

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

Регулярные выражения сложно писать, сложно читать и сложно поддерживать/изменять.

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

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

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

Как выглядят регулярные выражения

В JavaScript регулярные выражения это объект, который может быть определён двумя способами.

Первый способ заключается в создании нового объекта RegExp с помощью конструктора:

Второй способ заключается в использовании литералов регулярных выражений:

Вы знаете что в JavaScript есть литералы объектов и литералы массивов? В нём также есть литералы regexp.

В приведённом выше примере hey называется шаблоном. В литеральной форме он находится между двумя слэшами, а в случае с конструктором объекта, нет.

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

Как они работают?

Регулярное выражение, которое мы определили выше как re1 , очень простое. Оно ищет строку hey без каки-либо ограничений: строка может содержать много текста, а слово hey находиться где-то в середине и регулярное выражение сработает. Строка может содержать только слово hey и регулярка опять сработает.

Это довольно просто.

Вы можете попробовать протестировать регулярное выражение с помощью метода RegExp.test(String) , который возвращает логическое ( boolean ) значение:

В примере выше мы просто проверили удовлетворяет ли «hey» шаблону регулярного выражения, который храниться в re1 .

Это проще простого, но вы уже знаете много о регулярных выражениях.

Закрепление

сработает независимо от того где находится hey внутри строки.

Если вы хотите найти строки, которые начинаются с hey , то используйте оператор ^ :

Если вы хотите найти строки, которые заканчиваются на hey , то используйте оператор $ :

Объединяя два предыдущих оператора вы можете найти строку, которая полностью совпадает с hey :

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

Поиск элементов по диапазону

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

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

Диапазоны можно комбинировать:

Поиск многократных совпадений элемента диапазона

Вы можете проверить содержит ли строка только один символ из диапазона с помощью символа — :

Инверсия шаблона

Символ ^ в начале шаблона привязывает его к началу строки.

Использование этого символа внутри диапазона инвертирует диапазон, поэтому:

Метасимволы

  • \d совпадает с любым числом, эквивалентно [0-9]
  • \D совпадает с любым символом, который не является числом, эквивалентно [^0-9]
  • \w совпадает с любым буквенно-числовым символом, эквивалентно [A-Za-z0-9]
  • \W совпадает с любым символом, который не является буквенно-числовым значением, эквивалентно [^A-Za-z0-9]
  • \s совпадает с любым пробельным символом: пробел, табуляция, символ новой строки и пробелы Unicode
  • \S совпадает с любым символом, который не является пробелом
  • \0 совпадает с null
  • \n совпадает с символом новой строки
  • \t совпадает с символом табуляции
  • \uXXXX совпадает с символом Unicode с кодом XXXX (требуется флаг u )
  • . совпадает с любым символовом, кроме символа новой строки (таким как \n ) (если вы не используете флаг s , объясним позже)
  • [^] совпадает с любым символом, включая символ новой строки. Полезно при работе с многострочными строками

Выбор в регулярных выражениях

Если вы хотите выбрать одну или другую строку, используйте оператор | .

Квантификаторы

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

Вы можете использовать квантификатор ? , который сделает этот символ необязательным. В нашем случае цифра должна встречаться 0 или 1 раз:

но что если мы хотим чтобы регулярное выражение срабатывало на несколько цифр?

Вы можете сделать это 4 способами, используя + , * , и .

Совпадает с одним или более (>=1) элементами:

Совпадает с 0 или более (>=0) элементами:

Совпадает точно с n количеством элементов:

Совпадает с диапазоном от n до m элементов:

m можно опустить и оставить второй предел без ограничений, чтобы было минимум n элементов:

Опциональные элементы

Следующий за элементом знак ? , сделает его необязательным:

Группы

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

Пример ниже ищет точное совпадение из 3 цифр за которым следует один или более буквенно-числовые символов:

Повторяющиеся символы, которые находятся после закрывающей группу скобки, относятся ко всей группе:

Захват групп

До сих пор мы видели, как тестировать строки и проверять, содержат ли они определенный шаблон.

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

Вы можете делать это с помощью групп, а точнее с помощью захвата групп.

По умолчанию, группы итак захватываются. Теперь вместо использования RegExp.test(String) , который просто возвращает логическое значение, мы будем использовать один из следующих методов:

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

Если совпадений не найдено, то он возвращает null .

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

Опциональные группы

Захват групп можно сделать опциональным с помощью (. )? . Если ничего не будет найдено, то в возвращаемый массив будет добавлен элемент undefined :

Ссылка на найденную группу

Каждой найденной группе присваивается число. $1 ссылается на первый элемент, $2 на второй, и так далее. Это полезно, когда мы будет говорить о замене части строки.

Именованный захват групп

Это новая возможность ES2020.

Группе можно назначить имя, а не просто слот в возвращаемом массиве:

Использование match и exec без групп

Существует разница при использовании match и exec без групп: в первом элементе массива будет находится не полностью найденная строка, а прямое совпадение:

Незахватываемые группы

Так как по умолчанию группы являются захватываемыми, нам нужен способ игнорировать некоторые группы в возвращаемом массиве. Это возможно с помощью незахватываемых групп, которые начинаются с (. ) .

Флаги

Вы можете использовать следующие флаги на любых регулярных выражениях:

  • g : ищет совпадения глобально
  • i : делает регулярное выражение не чувствительным к регистру
  • m : включает многострочный режим. В этом режиме ^ и $ совпадают с началом и концом всей строки. Без этого флага, с многострочными строками они совпадают с началом и концом каждой строки.
  • u : включает поддержку Unicode (добавлено в ES6/ES2015)
  • s : (новое в ES2020) сокращение от «single line», он позволяет . совпадать с символами новой строки

Флаги можно комбинировать, а также они добавляются в конец строки литерала:

или передаются вторым параметром в конструктор объекта RegExp:

Инспектирование регулярных выражений

Вы можете инспектировать свойства регулярных выражений:

  • source — строка шаблона
  • multiline — принимается значение true если установлен флаг m
  • global — принимается значение true если установлен флаг g
  • ignoreCase — принимается значение true если установлен флаг i
  • lastIndex

Экранирование

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

Границы строк

\b и \B позволяют определить находится ли строка в начале или конце слова:

  • \b совпадает если набор символов находится в начале или конце слова
  • \B совпадает если набор символов не находится в начале или конце слова

Замена с помощью регулярных выражений

Мы уже видели как нужно проверять строки на совпадение с шаблоном.

Также мы видели как можно извлекать часть строк соотвествующие шаблону в массив.

Теперь давайте рассмотрим как заменять части строки на основе шаблона.

У объекта String в JavaScript есть метод replace() , который можно использовать без регулярных выражений для одной замены в строке:

Этот метод также может принимать и регулярное выражение в качестве аргумента:

Использование флага g — это единственный способ заменить несколько вхождений в строке на ванильном JavaScript:

Группы позволяют нам делать больше причудливых вещей, менять местами части строк:

Вместо строки можно использовать функцию, чтобы делать ещё более интересные вещи. В неё будет передан ряд аргументов, таких как возвращают методы String.match(RegExp) или RegExp.exec(String) , где количество аргументов зависит от количества групп:

Жадность

Регулярные выражения называются жадными по умолчанию.

Возьмём например это регулярное выражение:

Предполагается, что нам нужно извлечь из строки сумму в долларах:

но что если у нас есть больше слов после числа, это отвлекает

Почему? Потому что регулярное выражение после знака $ совпадает с любым символом .+ и не останавливается пока не достигнет конца строки. Затем он останавливается, потому что \s? делает конечное пространство необязательным.

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

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

Опережение: соответствие строки в зависимости от того что за ней следует

Используйет ?= для поиска совпадений в строке за которой следует определённая подстрока

?! выполняет обратную операцию и находит совпадений в строке за которыми не следует определённая подстрока:

Ретроспектива: соответствие строки в зависимости от того что ей предшествует

Это новая возможность ES2020.

Опережение использует символ ?= . Ретроспектива использует ? :

Инверсия ретроспективы использует ? :

Регулярные выражения и Unicode

Флаг u является обязательным при работе с Unicode строками, в частности когда может понадобится обрабатывать строки в астральных плоскостях, которые не включены в первые 1600 символов Unicode.

Например эмодзи, но и только они.

Если вы не добавили этот флаг, то это просто регулярное выражение, которые должно найти совпадение одного символа, не будет работать, потому что для JavaScript этот эмодзи внутри представлен двумя символами:

Поэтому, всегда используйте флаг u .

Unicode, как и обычные символы, может обрабатывать диапазоны:

JavaScript проверяет внутренние коды представления, поэтому ? \u1F436 \u1F43A \u1F98A . Посмотрите полный список эмодзи чтобы увидеть коды и узнать их порядок.

Экранирование свойств Unicode

Как мы говорили выше, в шаблоне регулярного выражения вы можете использовать \d чтобы найти совпадение на любую цифру, \s чтобы найти совпадение на любой символ кроме пробела, \w чтобы найти совпадение на любой буквенно-числовой символ и т. д.

Экранирование свойств Unicode — это возможность ES2020, которая добавляет очень крутую функцию, расширяя эту концепцию на всех Unicode символы и добавляя \p<> и \P<> .

У любого Unicode символа есть набор свойств. Например Script определяет семейство языков, ASCII — это логическое значение равное true для ASCII символов и т.д. Вы можете положить это свойство в фигурные скобки и регулярное выражение будет проверять чтобы его значение было истинным:

ASCII_Hex_Digit — это ещё одно логическое свойство, которое проверяет содержит ли строка тольк валидные шестнадцатеричные цифры:

Существует много других логических свойств, которые вы можете проверить просто добавив их имя в фигурные скобки, включая Uppercase , Lowercase , White_Space , Alphabetic , Emoji и другие:

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

Прочитать больше обо всех свойствах вы можете здесь.

Примеры

Извлечение числа из строки

Предположим, что есть строка содержащая только одно число, которое нужно извлечь. /\d+/ должен сделать это:

Поиск E-mail адреса:

Простейший подход заключается в проверке безпробельных символов до и после знака @ , с помощью \S :

Однако, это упрощенный пример, так как под него попадает множество не валидных E-mail адресов.

Захват текста между двойными кавычками

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

Лучший способ сделать это — использовать захват групп, потому то мы знаем что наше совпадение должно начинаться и заканчиваться символом » , поэтому мы можем легко настроить шаблон, но также мы хотим удалить эти кавычки из результата.

Мы найдём то что нам нужно в result[1] :

Получение содержимого из HTML тега

Например получить содержимое из тега span , допуская при этом любое количество аргументов у тега:

Регулярные выражения

Истоки регулярных выражений лежат в теории автоматов и теории формальных языков. Эти области изучают вычислительные модели (автоматы) и способы описания и классификации формальных языков. В 1940-х гг. Уоррен Маккалок и Уолтер Питтс описали нервную систему, используя простой автомат в качестве модели нейрона. Математик Стивен Клини позже описал эти модели, используя свою систему математических обозначений, названную «регулярные множества». Кен Томпсон встроил их в редактор QED, а затем в редактор expr, awk, vi, Perl.

Регулярные выражения в Perl и Tcl происходят от реализации, написанной Генри Спенсером. Филип Хейзел разработал библиотеку англ. Perl-compatible regular expressions — Perl-совместимые регулярные выражения), которая используется во многих современных инструментах, таких как Apache.

В теории формальных языков

Регулярные выражения состоят из констант и операторов, которые определяют множества строк и множества операций на них соответственно. На данном конечном алфавите Σ определены следующие константы:

  • (пустое множество) ∅ .
  • (пустая строка (англ.)) ε обозначает строку, не содержащую ни одного символа. Эквивалентно «».
  • (строка) «a», где a — символ алфавита Σ, обозначает строку, состоящую из одного этого символа.

и следующие операции:

Синтаксис

Представление символов

Обычные символы (литералы) и специальные символы (метасимволы)

Большинство символов в регулярном выражении представляют сами себя за исключением специальных символов [ ] \ ^ $ . | ? * + ( ) < >, которые могут быть предварены символом \ (обратная косая черта) («экранированы», «защищены») для представления их самих в качестве символов текста. Можно экранировать целую последовательность символов, заключив её между \Q и \E .

Пример Соответствие
a\.? a. или a
a\\\\b a\\b
a\[F\] a[F]
\Q+-*/\E +-*/

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

Любой символ

Метасимвол . (точка) означает один любой символ.

Символьные классы (наборы символов)

Набор символов в квадратных скобках [ ] именуется символьным классом и позволяют указать интерпретатору регулярных выражений, что на данном месте в строке может стоять один из перечисленных символов. В частности, [абв] задаёт возможность появления в тексте одного из трёх указанных символов, а [1234567890] задаёт соответствие одной из цифр. Возможно указание диапазонов символов: например, [А-Яа-я] соответствует буквам русского алфавита. [4]

Если требуется указать символы, которые не входят в указанный набор, то используют символ ^ внутри квадратных скобок, например [^0-9] означает любой символ, кроме цифр.

Добавление в набор специальных символов путём экранирования — самый бесхитростный способ. Однако в современных регулярных выражениях унаследован также и традиционный подход — см. Традиционные регулярные выражения.

Позиция внутри строки

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

Представление Позиция Пример Соответствие
^ Начало строки ^a a aa aaa
$ Конец строки a$ aaa aa a
\b Граница слова a\b aa a aa a
\ba a aa a aa
\B Не граница слова \Ba\B a a a a a a
\G Предыдущий успешный поиск \Ga aaa aaa (поиск остановился на 4-й позиции — там, где не нашлось a )

Квантификация (поиск последовательностей)

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

Представление Число повторений Пример Соответствие
<n> Ровно n colou<3>r colouuur
<m,n> От m до n включительно colou<2,4>r colouur , colouuur , colouuuur
<m,> Не менее m colou<2,>r colouur , colouuur , colouuuur и т. д.
<,n> Не более n colou<,3>r color , colour , colouur , colouuur
Представление Число повторений Эквивалент Пример Соответствие
* Ноль или более colou*r color , colour , colouur и т. д.
+ Одно или более colou+r colour , colouur и т. д. (но не color )
? Ноль или одно colou?r color , colour

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

Символьные классы в сочетании с квантификаторами позволяют устанавливать соответствия с реальными текстами. Например, столбцами цифр, телефонами, почтовыми адресами, элементами

Если символы < >не образуют квантификатор, их специальное значение игнорируется.

Жадная и ленивая квантификация

Выражение ( ) соответствует строке, содержащей несколько тегов

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

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

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

В некоторых реализациях квантификаторам в регулярных выражениях соответствует максимально длинная строка из возможных (квантификаторы являются жадными, англ. greedy ). Это может оказаться значительной проблемой. Например, часто ожидают, что выражение ( ) найдёт в тексте теги

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

Эту проблему можно решить двумя способами.

  1. Учитывать символы, не соответствующие желаемому образцу ( ]*> для вышеописанного случая).
  2. Определить квантификатор как нежадный (ленивый, англ.lazy ) — большинство реализаций позволяют это сделать, добавив после него знак вопроса.

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

Жадный Ленивый
* *?
+ +?
<n,> <n,>?

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

Ревнивая квантификация

Интерпретатор при поиске выражения ( a + a +)+ b в строке aaaaa пойдёт приблизительно по следующему пути:

  1. aaaaa
  2. aaaa a
  3. aaa a a
  4. aa aaa
  5. aa aa a
  6. aa a a a
  7. a a a a a — и только тут, потратив все точки возврата, сдастся

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

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

Жадный Ревнивый
* *+
? ?+
+ ++
<n,> <n,>+
Пример Соответствие
ab[xa]*+a abxaa bxa ; но не abxa abxa , так как буква a уже занята

Группировка

Обозначение группы

Круглые скобки используются для определения области действия и приоритета операций. Шаблон внутри группы обрабатывается как единое целое и может быть квантифицирован. Например, выражение (gr[ae]y-?)* найдёт последовательность вида grey-gray-grey-grey-gray .

Обратная связь

Одно из применений группировки — повторное использование ранее найденных групп символов (подстрок, блоков, отмеченных подвыражений). При обработке выражения подстро́ки, найденные по шаблону внутри группы, сохраняются в отдельной области памяти и получают номер начиная с единицы. Квантификация группы не влияет на сохранённый результат, то есть сохраняется лишь первое вхождение. Обычно поддерживается до 9 нумерованных подстрок с номерами от 1 до 9, но некоторые интерпретаторы позволяют работать с бо́льшим количеством. В последствии в пределах данного регулярного выражения можно использовать обозначения от \1 до \9 для проверки на совпадение с ранее найденной подстрокой.

Например, регулярное выражение (grey|gray)-\1 найдёт строку grey-grey или gray-gray , но пропустит строку grey-gray .

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

Группировка без обратной связи

Если группа используется только для группировки и её результат в дальнейшем не потребуется, то можно использовать группировку вида (?:шаблон) . Под результат такой группировки не выделяется отдельная область памяти и, соответственно, ей не назначается номер. Это положительно влияет на скорость выполнения выражения, но понижает удобочитаемость.

Атомарная группировка

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

Пример Соответствие Создаваемые группы
a(bc|b|x)cc abcc axcc
a(?:bc|b|x)cc нет
a(?>bc|b|x)cc abcc axcc

но не abcc axcc : вариант bc найден, остальные проигнорированы

a(?>x*)xa не найдётся axxxa : все x заняты, и нет возврата внутрь группы

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

Модификаторы

Модификаторы действуют с момента вхождения и до конца регулярного выражения или противоположного модификатора. Некоторые интерпретаторы могут применить модификатор ко всему выражению, а не с момента его вхождения.

Синтаксис Описание
(?i) Включает нечувствительность выражения к регистру символов (англ. case insensitivity )
(?-i) Выключает
(?s) Включает режим соответствия точки символам переноса строки и возврата каретки
(?-s) Выключает
(?m) Символы ^ и $ вызывают соответствие только после и до символов новой строки
(?-m) с началом и концом строки
(?x) Включает режим без учёта пробелов между частями регулярного выражения и позволяет использовать # для комментариев
(?-x) Выключает

Группы-модификаторы можно объединять в одну группу: (?i-sm) . Такая группа включает режим i , m и выключает режим s . Если использование модификаторов требуется только в пределах группы, то нужный шаблон указывается внутри группы после модификаторов и двоеточия. Например, (?-i)(?i:tV)set найдёт TVset , но не TVSET .

Комментарии

Для добавления комментариев в регулярное выражение можно использовать группы-комментарии вида (?#комментарий) . Такая группа интерпретатором полностью игнорируется и не проверяется на вхождение в текст. Например, выражение А(?#тут комментарий)Б соответствует строке АБ .

Перечисление

Вертикальная черта разделяет допустимые варианты. Например, gray|grey соответствует gray или grey . Следует помнить, что перебор вариантов выполняется слева направо, как они указаны.

Если требуется указать перечень вариантов внутри более сложного регулярного выражения, то его нужно заключить в группу. Например, gray|grey или gr(a|e)y описывают строку gray или grey . В случае с односимвольными альтернативами предпочтителен вариант gr[ae]y , так как сравнение с символьным классом выполняется проще, чем обработка группы с проверкой на все её возможные модификаторы и генерацией обратной связи.

Просмотр вперёд и назад

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

Представление Вид просмотра Пример Соответствие
(?=шаблон) Позитивный просмотр вперёд Людовик(?=XVI) ЛюдовикXV, Людовик XVI, Людовик XVIII, ЛюдовикLXVII, ЛюдовикXXL
(?!шаблон) Негативный просмотр вперёд (с отрицанием) Людовик(?!XVI) Людовик XV, ЛюдовикXVI, ЛюдовикXVIII, Людовик LXVII, Людовик XXL
(? Позитивный просмотр назад (? Сергей Иванов , Игорь Иванов
(? Негативный просмотр назад (с отрицанием) (? Сергей Иванов, Игорь Иванов

Поиск по условию

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

Представление Пояснение Пример Соответствие
(?(?=если)то|иначе) Если операция просмотра успешна, то далее выполняется часть то , иначе выполняется часть иначе . В выражении может использоваться любая из четырёх операций просмотра. Следует учитывать, что операция просмотра нулевой ширины, поэтому части то в случае позитивного или иначе в случае негативного просмотра должны включать в себя описание шаблона из операции просмотра. (?(? ма м , п ап
(?(n)то|иначе) Если n-я группа вернула значение, то поиск по условию выполняется по шаблону то , иначе по шаблону иначе . (а)?(?(1)м|п) м ам , п а п

Версии регулярных выражений

Традиционные регулярные выражения в англ. basic regular expressions (BRE)) на данный момент определён

В данную версию включены метасимволы:

  • Звёздочка должна следовать после выражения, соответствующего единичному символу. Пример: [xyz]* .
  • Выражение \(блок\)* следует считать неправильным. В некоторых случаях оно соответствует нулю или более повторений строки блок . В других оно соответствует строке блок* .
  • Внутри символьного класса специальные значения символов, в основном, игнорируются. Особые случаи:
    • Чтобы добавить символ ^ в набор, его следует поместить туда не первым.
    • Чтобы добавить символ — в набор, его следует поместить туда первым или последним. Например:
      • шаблон DNS-имени, куда могут входить буквы, цифры, минус и точка-разделитель: [-0-9a-zA-Z.] ;
      • любой символ, кроме минуса и цифры: [^-0-9] .
    • Чтобы добавить символ [ или ] в набор, его следует поместить туда первым. Например:
      • [][ab] соответствует ] , [ , a или b .

Расширенные регулярные выражения в стандарте POSIX

Синтаксис расширенных регулярных выражений англ. extended regular expressions (ERE)) в основном аналогичен традиционному.

  • Отменено использование обратной косой черты для метасимволов < >и ( ) .
  • Обратная косая черта перед метасимволом отменяет его специальное значение (см. Представление специальных символов).
  • Отвергнута теоретически нерегулярная конструкция \n .
  • Добавлены метасимволы + , ? , | .

Регулярные выражения, совместимые с Основная статья: англ. Perl-compatible regular expressions (PCRE)) имеют более богатый и в то же время предсказуемый синтаксис, чем даже POSIX ERE. По этой причине очень многие приложения используют именно Perl-совместимый синтаксис регулярных выражений.

Реализации

  • NFA (англ.nondeterministic finite-state automata — недетерминированные конечные автоматы) используют жадный алгоритм отката, проверяя все возможные расширения регулярного выражения в определённом порядке и выбирая первое подходящее значение. NFA может обрабатывать подвыражения и обратные ссылки. Но из-за алгоритма отката традиционный NFA может проверять одно и то же место несколько раз, что отрицательно сказывается на скорости работы. Поскольку традиционный NFA принимает первое найденное соответствие, он может и не найти самое длинное из вхождений (этого требует стандарт GNU sed). Именно такой механизм регулярных выражений используется, например, в Tcl и .NET.
  • DFA (англ.deterministic finite-state automata — детерминированные конечные автоматы) работают линейно по времени, поскольку не используют откаты и никогда не проверяют какую-либо часть текста дважды. Они могут гарантированно найти самую длинную строку из возможных. DFA содержит только конечное состояние, следовательно, не обрабатывает обратных ссылок, а также не поддерживает конструкций с явным расширением, то есть не способен обработать и подвыражения. DFA используется, например, в egrep.

Примечания

  1. java.sun.com
  2. MSDN
  3. Во многих книгах используются символы ∪ , + или ∨ вместо | .
  4. Для использования последовательностей букв необходимо установить правильную кодовую страницу в которой эти последовательности будут идти в порядке от и до указанных символов. Для русского языка это ISO 8859-5 и Юникод, так как в DOS-855, DOS-866 и KOI8-R русские буквы не идут одной целой группой или не упорядочены по алфавиту.

Литература

  • Фридл, Дж. Регулярные выражения. — СПб.: «Питер», 2001. — 352 с. — (Библиотека программиста). — ISBN 5-318-00056-8
  • Смит, Билл. Методы и алгоритмы вычислений на строках (regexp) = Computing Patterns in Strings. — М.: «Вильямс», 2006. — 496 с. — ISBN 0-201-39839-7
  • Форта, Бен. Освой самостоятельно регулярные выражения. 10 минут на урок = Sams Teach Yourself Regular Expressions in 10 Minutes. — М.: «Вильямс», 2005. — 184 с. — ISBN 5-8459-0713-6

Ссылки

  • Практическое использование регулярных выражений для веб-программирования
  • Справочник и ресурсы по регулярным выражениям (англ.) — учебник и детальное описание синтаксиса с примерами, сравнение различных интерпретаторов и прочее
  • MSDN (англ.)
  • MSDN — Знакомство с регулярными выражениями (рус.)
  • Онлайн-редактор регулярных выражений (PCRE) с полной подсветкой синтаксиса (java-applet) (англ.)
  • Сборник регулярных выражений в разных форматах (англ.)
  • Полезные ссылки по регулярным выражениям — каталог полезных ссылок по использованию регулярных выражений в различных языках программирования
  • Программа на JavaScript для тестирования регулярных выражений (англ.)
  • Проверка регулярных выражений
  • Онлайн-валидатор регулярных выражений для JavaScript (англ.)
  • Программа-валидатор регулярных выражений для .NET (рус.)

Wikimedia Foundation . 2010 .

Смотреть что такое «Регулярное выражение» в других словарях:

регулярное выражение — — [http://www.iks media.ru/glossary/index.html?gloss >Справочник технического переводчика

помеченное регулярное выражение — — [Л.Г.Суменко. Англо русский словарь по информационным технологиям. М.: ГП ЦНИИС, 2003.] Тематики информационные технологии в целом EN tagged regular expression … Справочник технического переводчика

РЕГУЛЯРНОЕ СОБЫТИЕ — множество слов конечного алфавита, к рое на алгебраич. языке может быть задано с использованием выражений специального вида р е г у л я р н ы х в ы р а ж е н и й. Пусть А конечный алфавит и символы операций, наз. о б ъ е д и н е н и е м, к о н к… … Математическая энциклопедия

Грамматика, разбирающая выражение — (РВ грамматика) это тип аналитической формальной грамматики, описывающей формальный язык в терминах набора правил для распознавания строк языка. Грамматика, разбирающая выражение, в сущности, представляет собой синтаксический анализатор… … Википедия

bash — У этого термина существуют и другие значения, см. Bash (значения). GNU Bourne Again SHell Типичная сессия в bash … Википедия

ECMAScript — Класс языка: мультипарадигменный: объектно ориентированное, обобщённое, функциональное, императивное, аспектно ориентированное, событийно ориентированное, прототипное программирование Появился в: 1995 Автор(ы) … Википедия

Жадность (регулярные выражения) — Жадность (в отношении регулярного выражения) характеристика, указывающая на поведение регулярного выражения при обработке шаблона. Жадное регулярное выражение «стремится» захватить максимально возможный текст (например, указание «один или более… … Википедия

Регулярные выражения — (англ. regular expressions, сокр. RegExp, RegEx, жарг. регэкспы или регексы) это формальный язык поиска и осуществления манипуляций с подстроками в тексте, основанный на использовании метасимволов (символов джокеров,… … Википедия

Регексп — Регулярные выражения (англ. regular expressions, сокр. RegExp, RegEx, жарг. регэкспы или регексы) система синтаксического разбора текстовых фрагментов по формализованному шаблону, основанная на системе записи образцов для поиска. Образец (англ.… … Википедия

Регексы — Регулярные выражения (англ. regular expressions, сокр. RegExp, RegEx, жарг. регэкспы или регексы) система синтаксического разбора текстовых фрагментов по формализованному шаблону, основанная на системе записи образцов для поиска. Образец (англ.… … Википедия

30 примеров полезных регулярных выражений

Регулярные выражения — мощный инструмент, который должен быть в арсенале каждого разработчика. С их помощью можно находить совпадения в строках на основе довольно сложных шаблонах. Используя регулярные выражения при создании динамических веб-сайтов, разработчик экономит кучу времени.

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

Изучение регулярных выражений ( regex ) довольно сложный процесс, особенно для начинающих, но при правильном подходе, вы освоите чрезвычайно мощный и полезный инструмент.

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

Как известно, регулярные выражения не «привязаны» к какому-то определенному языку программирования, поэтому вы можете использовать приведенные ниже примеры выражений при разработке проектов на различных языках. Например, на JavaScript, PHP или Python.

Проверка надежности пароля

Надежность пароля — довольно субъективное понятие, поэтому не существует универсального решения для проверки. Однако, приведенный выше пример регулярного выражения может стать хорошей отправной точкой, если вы не желаете придумывать выражение для проверки пароля с нуля.

Код цвета в шестнадцатеричном формате

Шестнадцатеричные коды цветов используются при веб-разработке очень часто. Это регулярное выражение может быть поможет сравнить: совпадает ли какая-либо строка с шаблоном шестнадцатеричного кода.

Проверка адреса электронной почты

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

IP-адрес (v4)

Как e-mail может использоваться для идентификации посетителя, так IP-адрес является идентификатором конкретного компьютера в сети. Приведенное регулярное выражение проверяет соответствие строки формату IP-адреса v4.

IP-адрес (v6)

Вы также можете проверить строку на соответствие формату IP-адреса новой, шестой версии более продвинутым регулярным выражением.

Разделитель в больших числах

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

Добавление протокола перед гиперссылкой

Независимо от того, с каким языком вы работаете: JavaScript, Ruby или PHP, это регулярное выражение может оказаться очень полезным. С его помощью проверяется любой URL-адрес на наличие в строке протокола, и если протокол отсутствует, указанный код добавляет его в начало строки.

«Вытягиваем» домен из URL-адреса.

Как известно, любой URL-адрес состоит из нескольких частей: вначале указывается протокол (HTTP или HTTPS), иногда за ним идет субдомен, а в завершении добавляется путь к странице. Вы можете использовать это выражение, чтобы вернуть только доменное имя, исключив все остальные части адреса.

Сортировка ключевых фраз по количеству слов

Это действительно полезные выражения для пользователей Google Analytics и инструмента для веб-мастеров. Ведь с помощью них можно отсортировать ключевые фразы, используемые посетителями при поиске по количеству слов, входящих в них.

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

Поиск валидной строки Base64 в PHP

Если вы являетесь PHP-разработчиком, то иногда вам может понадобиться найти объект, закодированный в формате Base64. Указанное выше выражение может использоваться для поиска закодированных строк в любом PHP-коде.

Проверка телефонного номера

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

Проверка телефонных номеров может стать довольно сложной задачей, поэтому автор статьи рекомендует детально ознакомиться с различными вариантами решения на сайте stackoverflow.com

Для проверки российских телефонных номеров используйте следующее выражение:

Начальные и конечные пробелы

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

«Вытягиваем» HTML-код изображения

Если по какой-либо причине вам необходимо «вытянуть» HTML-код изображения прямо из кода страницы, это регулярное выражение станет для вас идеальным решением. Хотя оно может без проблем работать на стороне сервера, для фронтенд-разработчиков приоритетней будет использовать метод attr() библиотеки jQuery вместо указанного регулярного выражения.

Проверяем дату на соответствие формату DD/MM/YYYY

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

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

Совпадение строки с адресом видеоролика на YouTube

На протяжении нескольких лет на Youtube не меняется структура URL-адресов. Youtube является самым популярным видео хостингом в Интернет, благодаря этому, видео с Youtube набирают наибольший трафик.

Если вам необходимо получить ID какого-либо видеоролика с Youtube, воспользуйтесь приведенным выше регулярным выражением. Это наилучшее выражение, подходящее для всех вариантов URL-адресов на этом видео-хостинге.

Проверка ISBN

Информация обо всех печатные изданиях, хранится в системе, известной как ISBN, которая состоит из 2 систем: ISBN-10 и ISBN-13. Неспециалисту очень сложно увидеть различия между этими системами. Однако, представленное выше регулярное выражение позволяет проверять соответствие кода ISBN сразу обоим системам: будь то ISBN-10 или ISBN-13. Код написан на PHP, поэтому это решение подходит исключительно для веб-разработчиков.

Проверка почтового индекса (Zip Code)

Автор этого регулярного выражения не только придумал его, но и еще нашел время его описать. Это выражение будет полезно вам, если вы проверяете совпадение строки со стандартным пятизначным индексом или его удлиненным вариантом, содержащим 9 знаков. Обращаем ваше внимание, что это выражение подходит только для проверки американских почтовых индексов. Для индексов других стран необходима настройка.

Для проверки российских почтовых индексов используйте следующее выражение:

Проверка правильности имени пользователя Twitter

Это небольшое регулярное выражение помогает найти имя пользователя Twitter внутри текста. Оно проверяет наличие имени в твитах по шаблону: @username .

Проверка номера кредитной карты

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

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

Поиск CSS-атрибутов

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

Этот код можно использовать когда будет необходимо «вытянуть» какое-либо CSS-правило из списка правил для какого-нибудь селектора.

Удаление комментариев в HTML

Если вам необходимо удалить все комментарии из блока HTML-кода, воспользуйтесь этим регулярным выражением. Чтобы получить желаемый результат, вы можете воспользоваться PHP-функцией preg_replace() .

Проверка на соответствие ссылке на Facebook-аккаунт

Если вам необходимо узнать у посетителя вашего сайта адрес его странички в Facebook, попробуйте это регулярное выражение. Оно поможет вам проверить правильность указанного пользователем URL. Этот код отлично подходит для проверки ссылок в этой соцсети.

Проверка версии Internet Explorer

Несмотря на то, что Microsoft выпустил новый браузер Edge, многие пользователи до сих пор пользуются Internet Explorer. Веб-разработчикам часто приходится проверять версию этого браузера, чтобы учитывать особенности разных версий при работе над своими проектами.

Вы можете использовать это регулярное выражения в JavaScript-коде чтобы узнать какая версия IE (5-11) используется.

«Вытягиваем» цену из строки

Цена какого-либо товара может быть указана в различных форматах: в ней могут встречаться запятые, знаки после запятой и символы валюты.

Указанное выше регулярное выражение учитывает различные форматы отображения цены, с его помощью вы сможете «вытянуть» цену из любой символьной строки.

Разбираем заголовки в e-mail

С помощью этого небольшого выражения вы сможете разобрать заголовок e-mail сообщения, чтобы извлечь оттуда список адресатов. Выражение может быть использовано и в случае, если адресатов несколько.

Вместо регулярных выражений, для разбора заголовков e-mail вы можете воспользуйтесь библиотекой на PHP .

Соответствие имени файла определенному типу

Если в вашем приложении существует возможность загрузки файлов на сервер, это регулярное выражение может помочь вам проверить файлы перед тем как посетитель их загрузит.

С помощью этого кода можно получить расширение загружаемого файла и проверить присутствует ли оно в списке разрешенных к загрузке.

Соответствие строки формату URL

Регулярное выражение может проверять URL-адреса с указанием протоколов HTTP и HTTPS на предмет соответствия синтаксису доменов TLD.

Существует простой способ проверки с использованием JavaScript RegExp .

Добавление атрибута rel=”nofollow” в теге ссылки

Если вы много работаете с HTML-кодом, то вам захочется автоматизировать часто повторяющиеся действия. Регулярные выражения отлично подходят для решения этой задачи и сэкономят много вашего времени.

Используя приведенный код, например, совместно с PHP, вы сможете «вытянуть» код ссылок из блоков HTML-кода и добавить в каждую из них атрибут rel=”nofollow” .

Работа с media query

Вы можете разбивать строки содержащие медиа-запросы на части, состоящие из параметров и свойств. Указанное выражение может быть полезно для анализа стороннего CSS-кода. Используя его вы сможете, например, более подробно понять как устроен чужой код.

Синтаксис поисковых выражений Google

Вы можете составить свои собственные регулярные выражения для манипулирования результатами поиска по вашим запросам в поисковой системе Google. Например, знак плюс (+) добавляет дополнительные ключевые слова, а минус (-) означает, что слова должны быть проигнорированы и удалены из результатов.

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

Заключение

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

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

Часть 1. Диалекты и возможности. Составление регулярных выражений

Серия контента:

Этот контент является частью # из серии # статей: Секреты регулярных выражений (regular expressions)

Этот контент является частью серии: Секреты регулярных выражений (regular expressions)

Следите за выходом новых статей этой серии.

1. Введение. Используем ли мы регулярные выражения в полной мере?

Если задуматься над вопросом: «А что такое «регулярное выражение» вообще?», то ответ найдётся не сразу. Можно сказать, что это специализированный язык описания символьного шаблона (последовательности символов) поиска в строках текста. Здесь важно то, что при поиске совпадений выполняется именно посимвольное сравнение. Автор энциклопедии по регулярным выражениям (Mastering Regular Expressions) Джеффри Фридл (J.E.F. Friedl) советует развивать привычку буквально интерпретировать регулярные выражения. Например, глядя на шаблон «^cat», обозначающий «строка должна начинаться со слова cat», следует рассуждать так: «совпадение будет найдено, если мы находимся в начале строки и обнаруживаем символ c, непосредственно за которым располагается символ a, сразу после которого находится символ t». Это позволяет максимально точно оценить смысл и сущность регулярного выражения.

Большинство пользователей знают, что для поиска достаточно задать слово-образец. Например, в Web-браузере в поле «Поиск» после ввода «Linux» вы получите длинный список ссылок на страницы, в тексте которых найдено совпадение с заданным шаблоном «Linux». В локальной файловой системе используется команда grep «Linux» или графические средства поиска.

Не все, но многие пользователи умеют применять метасимволы (* . ?) в шаблонах поиска. Ещё меньшее количество людей знает о возможности применения модификаторов и других изощрённых средств для конструирования регулярных выражений, т.е. во многих случаях мощность механизма регулярных выражений используется едва ли на треть. Отчего бы не попытаться увеличить к.п.д.?

2. Различные диалекты регулярных выражений. Соответствие стандарту POSIX

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

Программы vi(m), sed, grep, less, ed, expr, lex понимают только простые регулярные выражения, а утилиты (g)awk, egrep, а также интерпретаторы языков Perl, Tcl, Python – расширенные регулярные выражения. В то же время в каждой из программ существуют собственные усовершенствования, т.е. создаются поддиалекты регулярных выражений. Рассмотрим сходства и различия этих диалектов.

2.1. Общая схема регулярного выражения

Как правило, регулярное выражение состоит из трёх основных частей:

  1. Якорь – определяет позицию шаблона в строке текста:
    • ^ – якорь, определяющий начало строки;
    • $ – якорь, определяющий конец строки.
  2. Набор (последовательность) символов – для поиска соответствий в заданных позициях строки текста:
    • символ «точка» (.) соответствует любому произвольному символу;
    • алфавитно-цифровые символы и пробел представляют сами себя;
    • прочие символы – интерпретация зависит от диалекта.
  3. Модификатор – задаёт количество повторов предыдущего символа или набора символов (в зависимости от диалекта):
    • * – любое количество повторов символа/набора, в том числе и нулевое;
    • ? – соответствует нулю или одному экземпляру символа/набора;
    • + – соответствует одному или большему количеству экземпляров символа/набора.

Пример: необходимо найти все директивы определения макроконстант в исходном коде на языке С.

Здесь учтено, что в начале строки макроопределения может быть вставлено любое количество пробелов или же пробелы отсутствуют. Часть шаблона #define является литеральной, т.е. каждый символ интерпретируется «как есть». Заключительная часть шаблона означает «любые символы в любых количествах».

Отметим, что символ ^ интерпретируется как якорь, обозначающий начало строки, только в том случае, если он является самым первым символом шаблона. Точно так же символ $ обозначает конец строки при условии, что является самым последним символом шаблона. Во всех прочих случаях эти символы становятся литералами, т.е. представляют сами себя.

2.2. Определение диапазонов символов в регулярных выражениях

Если возникает необходимость задать символ из определённой группы, например, только цифровой символ, или только гласную букву нижнего регистра, или только символы пунктуации, то используются квадратные скобки, внутри которых определяются требуемые символы. Таким образом:

  • [012345789] – соответствует одному цифровому символу из заданного набора;
  • [аеёиоуыэюя] – соответствует одной из перечисленных гласных букв;
  • [. ;] – соответствует одному из символов пунктуации.

Обратите внимание на то, что в последнем случае точка в квадратных скобках утрачивает свой особый статус и обозначает не «любой символ», а собственно символ «точка».

Непрерывные диапазоны символов можно записывать в сокращённой форме с использованием дефиса: первый пример удобнее записать в виде [0–9]. Кроме того, допускаются любые сочетания диапазонов и конкретных символов.

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


  • [^0-9] – соответствует любому символу, кроме цифрового;
  • [^аеёиоуыэюя] – соответствует любой НЕ гласной букве.

С прочими нюансами определения диапазонов символов в квадратных скобках будем знакомиться в процессе их применения, а сейчас рассмотрим модификаторы на примере шаблона поиска цифрового IP-адреса.

2.3. Модификаторы количества повторений символов

Здесь сложность состоит в том, что модификатор * для поиска IP-адреса не годится – попытка использовать шаблон [0-9]*\.[0-9]*\.[0-9]*\.[0-9] приведёт к выводу строк, содержащих элементы типа 2344.5657.11.00000, не являющихся IP-адресами. Для уточнения количества повторений наборов символов применяется модификатор \. Зная, что в каждой части IP-адреса может содержаться от одной до трёх цифр, запишем модификатор в виде \<1,3\>. Символы «обратный слэш» перед точками необходимы для того, чтобы отменить их специальный статус универсального метасимвола. Также следует учесть, что значение 0 не используется в качестве первого байта обычных IP-адресов. В итоге получим следующий шаблон поиска:

Модификатор \ работает только в простых регулярных выражениях. В расширенных регулярных выражениях нельзя использовать конструкции \< \>, но можно применять модификатор ? в качестве эквивалента выражения \<0,1\>, а модификатор + как эквивалент выражения \<1,\>. Во втором случае после запятой не указано числовое значение – это означает, что максимальное количество совпадений не ограничено.

2.4. Запоминание и повторное использование элемента шаблона

Этот механизм также работает только в простых регулярных выражениях. (Впрочем, в языках программирования Perl, Python и т.п. данный механизм поддерживается – граница между диалектами становится всё менее различимой, помните?)

В простых регулярных выражениях части шаблона, заключённые внутри конструкции \( \), запоминаются и нумеруются, после чего их можно использовать повторно. Всего можно запомнить до девяти пронумерованных шаблонов. Наиболее показательным примером использования механизма запоминания является поиск палиндромов (слов, которые одинаково читаются как слева направо, так и справа налево):

  • \([a-z]\)\([a-z]\)[a-z]\2\1 – для пятибуквенных палиндромов (например, level, rotor, madam и т.д.)
  • \([a-z]\)\([a-z]\)\([a-z]\)\3\2\1 – для шестибуквенных палиндромов (например, redder, succus, terret и т.д.)

2.5. Соответствие стандарту POSIX

Стандарт POSIX также делит регулярные выражения на две категории: BRE (Basic Regular Expressions) и ERE (Extended Regular Expressions). В обеих категориях поддерживаются метасимволы . и *, якоря ^ и $, группирование символов в скобках (для BRE скобки экранируются обратным слэшем), применение квантификаторов \ к группам в скобках. Запоминание и повторное использование \1. \9 поддерживает только категория BRE, а квантификаторы + и ? и конструкцию выбора – только категория ERE.

В стандарте POSIX используется понятие локального контекста (locale) – совокупности параметров, описывающих языковые и культурные правила: формат даты и времени, интерпретация символов активной кодировки и т.д. Это не относится напрямую к регулярным выражениям, но влияет на их функционирование. При работе в локальном контексте с кодировкой UTF-8, принятой почти во всех современных дистрибутивах, корректно обрабатываются символы русского алфавита и их диапазоны, т.е. можно указывать диапазоны [а-я] и [А-Я] в шаблонах поиска.

3. Примеры составления полезных регулярных выражений

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

3.1. Пример шаблона для поиска денежной суммы, записываемой в формате «10000 руб. 00 коп.»

Необходимое пояснение: если в модификаторе типа \ отсутствует и запятая, и максимальное значение, то такая конструкция задаёт точное количество ожидаемых повторов элемента шаблона. В нашем примере определяются ровно два цифровых символа для обозначения копеек.

3.2. Пример шаблона для поиска URL-строки, соответствующей Web-ресурсу в Интернете:

Необходимое пояснение: дефис теряет своё специальное значение, если он указан в самой первой позиции сразу после открывающей квадратной скобки в диапазоне. По данному шаблону могут быть найдены и такие «экзотические» URL-строки, как, например, http://my.home-server/

В формате расширенных регулярных выражений этот шаблон можно было бы записать более компактно:

Такую запись понимают, например, утилиты egrep и awk.

3.3. Шаблон для поиска любого HTML-тэга выглядит на удивление просто:

Совпадает с любой последовательностью символов за исключением > в количестве от одного и более, заключённой в угловые скобки. Иными словами, будет найден и односимвольный тэг

, и более «многословные» тэги, подобные .

3.4. Вариант шаблона для поиска дат

Расширенные регулярные выражения позволяют написать несколько громоздкий, но тем не менее корректно работающий шаблон для поиска дат, имеющих вид «13 ноября 2009 г.»:

Недостаток этого шаблона заключается в том, что с его помощью невозможно найти даты из древней истории, например, «13 ноября 245 г.» или 1 января 88 г.», но для работы с современными документами он вполне годится (учитываем контекст поиска!).

3.5. Практическое применение нумерованных частей шаблона

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

С помощью такого шаблона можно находить шестисимвольные палиндромы не только на английском, но и на русском и на любых других языках, а также последовательности символов, не относящихся к алфавитным, например /*!!*/

Более практичным способом использования запомненных и пронумерованных частей шаблона является поиск стоящих рядом повторяющихся слов, что позволяет обнаружить такие часто встречающиеся в текстах ошибки (опечатки), как «для для». Шаблон можно записать так:

Здесь применяются ещё два элемента регулярных выражений: \ для обозначения конечной границы слова. Таким образом, мы запоминаем только отдельные слова, а не любые последовательности символов. Выражение ..* соответствует любому слову, состоящему по крайней мере из одного символа. В результате мы сможем найти такие опечатки-повторения, как «и и», «не не», «для для» и т.п.

3.6. Ограничение размера совпадающей части шаблона

Ещё одна особенность «характера» регулярных выражений – они являются неимоверно «жадными» (greedy), т.е. стремятся обеспечить совпадение с как можно более длинной строкой. Из-за этой «жадности» могут возникать неожиданные проблемы. Например, имеется шаблон для поиска любого количества символов, заключённых в кавычки:

Строки, в которых производится поиск, имеют следующий вид:

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

решает проблему только для первой строки, а во второй и третьей к фамилии подцепляется ещё и место работы – опять не то, что нам нужно!

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

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

4. Заключение

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

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

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

Регулярные выражения

— это объект, описывающий символьный шаблон. Класс RegExp в JavaScript представляет регулярные выражения, а объекты классов String и RegExp определяют методы, использующие регулярные выражения для выполнения поиска по шаблону и операций поиска в тексте с заменой. Грамматика регулярных выражений в языке JavaScript содержит достаточно полное подмножество синтаксиса регулярных выражений, используемого в языке Perl 5, поэтому, если вы имеете опыт работы с языком Perl, то вы без труда сможете описывать шаблоны в программах на языке JavaScript.

В число особенностей регулярных выражений языка Perl, которые не поддерживаются в ECMAScript, входят флаги s (однострочный режим) и x (расширенный синтаксис); управляющие последовательности \a, \e, \l, \u, \L, \U, \E, \Q, \A, \Z, \z и \G и другие расширенные конструкции, начинающиеся с (?.

Определение регулярных выражений

В JavaScript регулярные выражения представлены объектами RegExp. Объекты RegExp могут быть созданы посредством конструктора RegExp(), но чаще они создаются с помощью специального синтаксиса литералов. Так же как строковые литералы задаются в виде символов, заключенных в кавычки, литералы регулярных выражений задаются в виде символов, заключенных в пару символов слэша (/). Таким образом, JavaScript-код может содержать строки, похожие на эту:

Эта строка создает новый объект RegExp и присваивает его переменной pattern. Данный объект RegExp ищет любые строки, заканчивающиеся символом «s». Это же регулярное выражение может быть определено с помощью конструктора RegExp():

Спецификация шаблона регулярного выражения состоит из последовательности символов. Большая часть символов, включая все алфавитно-цифровые, буквально описывают символы, которые должны присутствовать. То есть регулярное выражение /java/ совпадает со всеми строками, содержащими подстроку «java».

Другие символы в регулярных выражениях не предназначены для поиска их точных эквивалентов, а имеют особое значение. Например, регулярное выражение /s$/ содержит два символа. Первый символ s обозначает поиск буквального символа. Второй, $ — это специальный метасимвол, обозначающий конец строки. Таким образом, это регулярное выражение соответствует любой строке, заканчивающейся символом s.

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

Символы литералов

Как отмечалось ранее, все алфавитные символы и цифры в регулярных выражениях соответствуют сами себе. Синтаксис регулярных выражений в JavaScript также поддерживает возможность указывать некоторые неалфавитные символы с помощью управляющих последовательностей, начинающихся с символа обратного слэша (\). Например, последовательность \n соответствует символу перевода строки. Эти символы перечислены в таблице ниже:

Символы в регулярных выражениях JavaScript

Символ Соответствие
Алфавитно-цифровые символы Соответствуют сами себе
\0 Символ NUL (\u0000)
\t Табуляция (\u0009)
\n Перевод строки (\u000A)
\v Вертикальная табуляция (\u000B)
\f Перевод страницы (\u000C)
\r Возврат каретки (\u000D)
\xnn Символ из набора Latin, задаваемый шестнадцатеричным числом nn; например, \x0A — это то же самое, что \n
\uxxxx Unicode-символ, заданный шестнадцатеричным числом xxxx; например, \u0009 — это то же самое, что \t
\cX Управляющий символ «X», например, последовательность \cJ эквивалентна символу перевода строки \n

Некоторые знаки препинания имеют в регулярных выражениях особый смысл:

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

Если вы не можете точно вспомнить, каким из символов должен предшествовать символ \, можете спокойно помещать обратный слэш перед любым из символов. Однако имейте в виду, что многие буквы и цифры вместе с символом слэша обретают специальное значение, поэтому тем буквам и цифрам, которые вы ищете буквально, не должен предшествовать символ \. Чтобы включить в регулярное выражение сам символ обратного слэша, перед ним, очевидно, следует поместить другой символ обратного слэша. Например, следующее регулярное выражение соответствует любой строке, содержащей символ обратного слэша: /\\/.

Классы символов

Отдельные символы литералов могут объединяться в классы символов путем помещения их в квадратные скобки. Класс символов соответствует любому символу, содержащемуся в этом классе. Следовательно, регулярное выражение /[abc]/ соответствует одному из символов a, b или c.

Могут также определяться классы символов с отрицанием, соответствующие любому символу, кроме тех, которые указаны в скобках. Класс символов с отрицанием задается символом ^ в качестве первого символа, следующего за левой скобкой. Регулярное выражение /[^abc]/ соответствует любому символу, отличному от a, b или c. В классах символов диапазон символов может задаваться при помощи дефиса. Поиск всех символов латинского алфавита в нижнем регистре осуществляется посредством выражения /[a-z]/, а любую букву или цифру из набора символов Latin можно найти при помощи выражения /[a-zA-Z0-9]/.

Некоторые классы символов используются особенно часто, поэтому синтаксис регулярных выражений в JavaScript включает специальные символы и для их обозначения. Так, \s соответствует символам пробела, табуляции и любым пробельным символам из набора Unicode, а \S — любым символам, не являющимся пробельными символами из набора Unicode.

В таблице ниже приводится перечень этих спецсимволов и синтаксиса классов символов. (Обратите внимание, что некоторые из управляющих последовательностей классов символов соответствуют только ASCII-символам и не расширены для работы с Unicode-символами. Можно явно определить собственные классы Unicode-символов, например, выражение /[\u0400-\u04FF]/ соответствует любому символу кириллицы.)

Классы символов регулярных выражений JavaScript

Символ Соответствие
[. ] Любой из символов, указанных в скобках
[^. ] Любой из символов, не указанных в скобках
. Любой символ, кроме перевода строки или другого разделителя Unicode-строки
\w Любой текстовый ASCII-символ. Эквивалентно [a-zA-Z0-9_]
\W Любой символ, не являющийся текстовым ASCII-символом. Эквивалентно [^a-zA-Z0-9_]
\s Любой пробельный символ из набора Unicode
\S Любой непробельный символ из набора Unicode. Обратите внимание, что символы \w и \S — это не одно и то же
\d Любые ASCII-цифры. Эквивалентно [0-9]
\D Любой символ, отличный от ASCII-цифр. Эквивалентно [^0-9]
[\b] Литерал символа «забой»

Обратите внимание, что управляющие последовательности специальных символов классов могут находиться в квадратных скобках. \s соответствует любому пробельному символу, а \d соответствует любой цифре, следовательно, /[\s\d]/ соответствует любому пробельному символу или цифре.

Повторение

Имея знания синтаксиса регулярных выражений, полученные к настоящему моменту, мы можем описать число из двух цифр как /\d\d/ или из четырех цифр как /\d\d\d\d/, но не сможем, например, описать число, состоящее из любого количества цифр, или строку из трех букв, за которыми следует необязательная цифра. Эти более сложные шаблоны используют синтаксис регулярных выражений, указывающий, сколько раз может повторяться данный элемент регулярного выражения.

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

Символы повторения в регулярных выражениях JavaScript

Символ Значение
Соответствует предшествующему шаблону, повторенному не менее n и не более m раз
Соответствует предшествующему шаблону, повторенному n или более раз
Соответствует в точности n экземплярам предшествующего шаблона
? Соответствует нулю или одному экземпляру предшествующего шаблона; предшествующий шаблон является необязательным. Эквивалентно
+ Соответствует одному или более экземплярам предшествующего шаблона. Эквивалентно
* Соответствует нулю или более экземплярам предшествующего шаблона. Эквивалентно

Следующие строки демонстрируют несколько примеров:

Будьте внимательны при использовании символов повторения * и ?. Они могут соответствовать отсутствию указанного перед ними шаблона и, следовательно, отсутствию символов. Например, регулярному выражению /a*/ соответствует строка «bbbb», поскольку в ней нет символа a.

Символы повторения, перечисленные в таблице, соответствуют максимально возможному количеству повторений, при котором обеспечивается поиск последующих частей регулярного выражения. Мы говорим, что это — «жадное» повторение. Имеется также возможность реализовать повторение, выполняемое «нежадным» способом. Достаточно указать после символа (или символов) повторения вопросительный знак: . +?, *? или даже <1,5>?.

Например, регулярное выражение /a+/ соответствует одному или более экземплярам буквы a. Примененное к строке «aaa», оно соответствует всем трем буквам. С другой стороны, выражение /a+?/ соответствует одному или более экземплярам буквы a и выбирает наименее возможное число символов. Примененный к той же строке, этот шаблон соответствует только первой букве a.

«Нежадное» повторение не всегда дает ожидаемый результат. Рассмотрим шаблон /a+b/, соответствующий одному или более символам a, за которыми следует символ b. Применительно к строке «aaab» ему соответствует вся строка.

Теперь проверим «нежадную» версию /a+?b/. Можно было бы подумать, что она должна соответствовать символу b, перед которым стоит только один символ a. В случае применения к той же строке «aaab» можно было бы ожидать, что она совпадет с единственным символом a и последним символом b. Однако на самом деле этому шаблону соответствует вся строка, как и в случае «жадной» версии. Дело в том, что поиск по шаблону регулярного выражения выполняется путем нахождения первой позиции в строке, начиная с которой соответствие становится возможным. Так как соответствие возможно, начиная с первого символа строки, более короткие соответствия, начинающиеся с последующих символов, даже не рассматриваются.

Альтернативы, группировка и ссылки

Грамматика регулярных выражений включает специальные символы определения альтернатив, подвыражений группировки и ссылок на предыдущие подвыражения. Символ вертикальной черты | служит для разделения альтернатив. Например, /ab|cd|ef/ соответствует либо строке «ab», либо строке «cd», либо строке «ef», а шаблон /\d<3>|[a-z]<4>/ — либо трем цифрам, либо четырем строчным буквам.

Обратите внимание, что альтернативы обрабатываются слева направо до тех пор, пока не будет найдено соответствие. При обнаружении совпадения с левой альтернативой правая игнорируется, даже если можно добиться «лучшего» соответствия. Поэтому, когда к строке «ab» применяется шаблон /a|ab/, он будет соответствовать только первому символу.

Круглые скобки имеют в регулярных выражениях несколько значений. Одно из них — группировка отдельных элементов в одно подвыражение, так что элементы при использовании специальных символов |, *, +, ? и других рассматриваются как одно целое. Например, шаблон /java(script)?/ соответствует слову «java», за которым следует необязательное слово «script», а /(ab|cd)+|ef)/ соответствует либо строке «ef», либо одному или более повторений одной из строк «ab» или «cd».

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

Предположим, что требуется отыскать одну или более букв в нижнем регистре, за которыми следует одна или несколько цифр. Для этого можно воспользоваться шаблоном /[a-z]+\d+/. Но предположим также, что нам нужны только цифры в конце каждого соответствия. Если поместить эту часть шаблона в круглые скобки (/[a-z]+(\d+)/), то можно будет извлечь цифры из любых найденных нами соответствий. Как это делается, будет описано ниже.

С этим связано еще одно применение подвыражений в скобках, позволяющее ссылаться на подвыражения из предыдущей части того же регулярного выражения. Это достигается путем указания одной или нескольких цифр после символа \. Цифры ссылаются на позицию подвыражения в скобках внутри регулярного выражения. Например, \1 ссылается на первое подвыражение, а \3 — на третье. Обратите внимание, что подвыражения могут быть вложены одно в другое, поэтому при подсчете используется позиция левой скобки. Например, в следующем регулярном выражении ссылка на вложенное подвыражение ([Ss]cript) будет выглядеть как \2:

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

Соответствия кавычек мы можем потребовать посредством такой ссылки:

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

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

Здесь подвыражение (?:[Ss]cript) необходимо только для группировки, чтобы к группе мог быть применен символ повторения ?. Эти модифицированные скобки не создают ссылку, поэтому в данном регулярном выражении \2 ссылается на текст, соответствующий шаблону (fun\w*).

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

Символы регулярных выражений выбора из альтернатив, группировки и ссылки JavaScript

Символ Значение
| Альтернатива. Соответствует либо подвыражению слева, либо подвыражению справа.
(. ) Группировка. Группирует элементы в единое целое, которое может использоваться с символами *, +, ?, | и т.п. Также запоминает символы, соответствующие этой группе для использования в последующих ссылках.
(. ) Только группировка. Группирует элементы в единое целое, но не запоминает символы, соответствующие этой группе.
\number Соответствует тем же символам, которые были найдены при сопоставлении с группой с номером number. Группы — это подвыражения внутри скобок (возможно, вложенных). Номера группам присваиваются путем подсчета левых скобок слева направо. Группы, сформированные с помощью символов (. не нумеруются.

Указание позиции соответствия

Как описывалось ранее, многие элементы регулярного выражения соответствуют одному символу в строке. Например, \s соответствует одному пробельному символу. Другие элементы регулярных выражений соответствуют позициям между символами, а не самим символам. Например, \b соответствует границе слова — границе между \w (текстовый ASCII-символ) и \W (нетекстовый символ) или границе между текстовым ASCII-символом и началом или концом строки.

Такие элементы, как \b, не определяют какие-либо символы, которые должны присутствовать в найденной строке, однако они определяют допустимые позиции для проверки соответствия. Иногда эти элементы называются якорными элементами регулярных выражений, потому что они закрепляют шаблон за определенной позицией в строке. Чаще других используются такие якорные элементы, как ^ и $, привязывающие шаблоны соответственно к началу и концу строки.

Например, слово «JavaScript», находящееся на отдельной строке, можно найти с помощью регулярного выражения /^JavaScript$/. Чтобы найти отдельное слово «Java» (а не префикс, например в слове «JavaScript»), можно попробовать применить шаблон /\sJava\s/, который требует наличия пробела до и после слова.

Но такое решение порождает две проблемы. Во-первых, оно найдет слово «Java», только если оно окружено пробелами с обеих сторон, и не сможет найти его в начале или в конце строки. Во-вторых, когда этот шаблон действительно найдет соответствие, возвращаемая им строка будет содержать ведущие и замыкающие пробелы, а это не совсем то, что нам нужно. Поэтому вместо шаблона, совпадающего с пробельными символами \s, мы воспользуемся шаблоном (или якорем), совпадающим с границами слова \b. Получится следующее выражение: /\bJava\b/.

Якорный элемент \B соответствует позиции, не являющейся границей слова. То есть шаблону /\B[Ss]cript/ будут соответствовать слова «JavaScript» и «postscript» и не будут соответствовать слова «script» или «Scripting».

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

Например, чтобы найти совпадение с названием распространенного языка программирования, за которым следует двоеточие, можно воспользоваться выражением /[Jj]ava([Ss]cript)?(?=\:)/. Этому шаблону соответствует слово «JavaScript» в строке «JavaScript: The Definitive Guide», но ему не будет соответствовать слово «Java» в строке «Java in a Nutshell», потому что за ним не следует двоеточие.

Если же ввести условие (. то это будет негативная опережающая проверка на последующие символы, требующая, чтобы следующие символы не соответствовали указанному шаблону. Например, шаблону /Java(?!Script)([A — Z]\w*)/ соответствует подстрока «Java», за которой следует заглавная буква и любое количество текстовых ASCII-символов при условии, что за подстрокой «Java» не следует подстрока «Script». Он совпадет со строкой «JavaBeans», но не совпадет со строкой «Javanese», совпадет со строкой «JavaScrip», но не совпадет со строками «JavaScript» или «JavaScripter».

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

Якорные символы регулярных выражений

Символ Значение
^ Соответствует началу строкового выражения или началу строки при многострочном поиске.
$ Соответствует концу строкового выражения или концу строки при многострочном поиске.
\b Соответствует границе слова, т.е. соответствует позиции между символом \w и символом \W или между символом \w и началом или концом строки. (Однако обратите внимание, что [\b] соответствует символу забоя.)
\B Соответствует позиции, не являющейся границей слов.
(?=p) Позитивная опережающая проверка на последующие символы. Требует, чтобы последующие символы соответствовали шаблону p, но не включает эти символы в найденную строку.
(?!p) Негативная опережающая проверка на последующие символы. Требует, чтобы следующие символы не соответствовали шаблону p.

Флаги

И еще один, последний элемент грамматики регулярных выражений. Флаги регулярных выражений задают высокоуровневые правила соответствия шаблонам. В отличие от остальной грамматики регулярных выражений, флаги указываются не между символами слэша, а после второго из них. В языке JavaScript поддерживается три флага.

Флаг i указывает, что поиск по шаблону должен быть нечувствителен к регистру символов, а флаг g — что поиск должен быть глобальным, т.е. должны быть найдены все соответствия в строке. Флаг m выполняет поиск по шаблону в многострочном режиме. Если строковое выражение, в котором выполняется поиск, содержит символы перевода строк, то в этом режиме якорные символы ^ и $, помимо того, что они соответствуют началу и концу всего строкового выражения, также соответствуют началу и концу каждой текстовой строки. Например, шаблону /java$/im соответствует как слово «java», так и «Java\nis fun».

Эти флаги могут объединяться в любые комбинации. Например, чтобы выполнить поиск первого вхождения слова «java» (или «Java», «JAVA» и т.д.) без учета регистра символов, можно воспользоваться нечувствительным к регистру регулярным выражением /\bjava\b/i. А чтобы найти все вхождения этого слова в строке, можно добавить флаг g: /\bjava\b/gi.

Методы класса String для поиска по шаблону

До этого момента мы обсуждали грамматику создаваемых регулярных выражений, но не рассматривали, как эти регулярные выражения могут фактически использоваться в JavaScript-сценариях. В данном разделе мы обсудим методы объекта String, в которых регулярные выражения применяются для поиска по шаблону, а также для поиска с заменой. А затем продолжим разговор о поиске по шаблону с регулярными выражениями, рассмотрев объект RegExp, его методы и свойства.

Строки поддерживают четыре метода, использующие регулярные выражения. Простейший из них — метод search(). Он принимает в качестве аргумента регулярное выражение и возвращает либо позицию первого символа найденной подстроки, либо -1, если соответствие не найдено. Например, следующий вызов вернет 4:

Если аргумент метода search() не является регулярным выражением, он сначала преобразуется путем передачи конструктору RegExp. Метод search() не поддерживает глобальный поиск и игнорирует флаг g в своем аргументе.

Метод replace() выполняет операцию поиска с заменой. Он принимает в качестве первого аргумента регулярное выражение, а в качестве второго — строку замены. Метод отыскивает в строке, для которой он вызван, соответствие указанному шаблону.

Если регулярное выражение содержит флаг g, метод replace() заменяет все найденные совпадения строкой замены. В противном случае он заменяет только первое найденное совпадение. Если первый аргумент метода replace() является строкой, а не регулярным выражением, то метод выполняет буквальный поиск строки, а не преобразует его в регулярное выражение с помощью конструктора RegExp(), как это делает метод search().

В качестве примера мы можем воспользоваться методом replace() для единообразной расстановки прописных букв в слове «JavaScript» для всей строки текста:

Метод replace() представляет собой более мощное средство, чем можно было бы предположить по этому примеру. Напомню, что подвыражения в скобках, находящиеся внутри регулярного выражения, нумеруются слева направо, и что регулярное выражение запоминает текст, соответствующий каждому из подвыражений. Если в строке замены присутствует знак $ с цифрой, метод replace() заменяет эти два символа текстом, соответствующим указанному подвыражению. Это очень полезная возможность. Мы можем использовать ее, например, для замены прямых кавычек в строке типографскими кавычками, которые имитируются ASCII-символами:

Важное, что следует отметить, — второй аргумент replace() может быть функцией, динамически вычисляющей строку замены.

Метод match() — это наиболее общий из методов класса String, использующих регулярные выражения. Он принимает в качестве единственного аргумента регулярное выражение (или преобразует свой аргумент в регулярное выражение, передав его конструктору RegExp()) и возвращает массив, содержащий результаты поиска. Если в регулярном выражении установлен флаг g, метод возвращает массив всех соответствий, присутствующих в строке. Например:

Если регулярное выражение не содержит флаг g, метод match() не выполняет глобальный поиск; он просто ищет первое совпадение. Однако match() возвращает массив, даже когда метод не выполняет глобальный поиск. В этом случае первый элемент массива — это найденная подстрока, а все оставшиеся элементы представляют собой подвыражения регулярного выражения. Поэтому если match() возвращает массив arr, то arr[0] будет содержать найденную строку целиком, arr[1] -подстроку, соответствующую первому подвыражению, и т.д. Проводя параллель с методом replace(), можно сказать, что в arr[n] заносится содержимое $n.

Например, взгляните на следующий программный код, выполняющий разбор URL-адреса:

Следует отметить, что для регулярного выражения, в котором не установлен флаг g глобального поиска, метод match() возвращает то же значение, что и метод exec() регулярного выражения: возвращаемый массив имеет свойства index и input, как описывается в обсуждении метода exec() ниже.

Последний из методов объекта String, в котором используются регулярные выражения — split(). Этот метод разбивает строку, для которой он вызван, на массив подстрок, используя аргумент в качестве разделителя. Например:

Метод split() может также принимать в качестве аргумента регулярное выражение. Это делает метод более мощным. Например, можно указать разделитель, допускающий произвольное число пробельных символов с обеих сторон:

Объект RegExp

Как было упомянуто, регулярные выражения представлены в виде объектов RegExp. Помимо конструктора RegExp(), объекты RegExp поддерживают три метода и несколько свойств.

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

Второй аргумент RegExp() может отсутствовать. Если он указан, то определяет флаги регулярного выражения. Это должен быть один из символов g, i, m либо комбинация этих символов. Например:

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

Свойства RegExp

Каждый объект RegExp имеет пять свойств. Свойство source — строка, доступная только для чтения, содержащая текст регулярного выражения. Свойство global — логическое значение, доступное только для чтения, определяющее наличие флага g в регулярном выражении. Свойство ignoreCase — это логическое значение, доступное только для чтения, определяющее наличие флага i в регулярном выражении. Свойство multiline — это логическое значение, доступное только для чтения, определяющее наличие флага m в регулярном выражении. И последнее свойство lastIndex — это целое число, доступное для чтения и записи. Для шаблонов с флагом g это свойство содержит номер позиции в строке, с которой должен быть начат следующий поиск. Как описано ниже, оно используется методами exec() и test().

Методы RegExp

Объекты RegExp определяют два метода, выполняющие поиск по шаблону; они ведут себя аналогично методам класса String, описанным выше. Основной метод класса RegExp, используемый для поиска по шаблону — exec(). Он похож на упоминавшийся метод match() класса String, за исключением того, что является методом класса RegExp, принимающим в качестве аргумента строку, а не методом класса String, принимающим аргумент RegExp.

Метод exec() выполняет регулярное выражение для указанной строки, т.е. ищет совпадение в строке. Если совпадение не найдено, метод возвращает null. Однако если соответствие найдено, он возвращает такой же массив, как массив, возвращаемый методом match() для поиска без флага g. Нулевой элемент массива содержит строку, соответствующую регулярному выражению, а все последующие элементы — подстроки, соответствующие всем подвыражениям. Кроме того, свойство index содержит номер позиции символа, которым начинается соответствующий фрагмент, а свойство input ссылается на строку, в которой выполнялся поиск.

В отличие от match(), метод exec() возвращает массив, структура которого не зависит от наличия в регулярном выражении флага g. Напомню, что при передаче глобального регулярного выражения метод match() возвращает массив найденных соответствий. А exec() всегда возвращает одно соответствие, но предоставляет о нем полную информацию. Когда exec() вызывается для регулярного выражения, содержащего флаг g, метод устанавливает свойство lastIndex объекта регулярного выражения равным номеру позиции символа, следующего непосредственно за найденной подстрокой.

Когда метод exec() вызывается для того же регулярного выражения второй раз, он начинает поиск с символа, позиция которого указана в свойстве lastIndex. Если exec() не находит соответствия, свойство lastIndex получает значение 0. (Вы также можете установить lastIndex в ноль в любой момент, что следует делать во всех тех случаях, когда поиск завершается до того, как будет найдено последнее соответствие в одной строке, и начинается поиск в другой строке с тем же объектом RegExp.) Это особое поведение позволяет вызывать exec() повторно для перебора всех соответствий регулярному выражению в строке. Например:

Еще один метод объекта RegExp — test(), который намного проще метода exec(). Он принимает строку и возвращает true, если строка соответствует регулярному выражению:

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

Руководство по регулярным выражениям в JavaScript

Введение в регулярные выражения

Регулярные выражения (RegExp) — это очень эффективный способ работы со строками.

Составив регулярное выражение с помощью специального синтаксиса вы можете:

  • искать текст в строке
  • заменять подстроки в строке
  • извлекать информацию из строки

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

Регулярные выражения относятся к 1950-м годам, когда они были формализованы как концептуальный шаблон поиска для алгоритмов обработки строк.

Регулярные выражения реализованные в UNIX, таких как grep, sed и популярных текстовых редакторах, начали набирать популярность и были добавлены в язык программирования Perl, а позже и в множество других языков.

JavaScript, наряду с Perl, это один из языков программирования в котором поддержка регулярных выражений встроена непосредственно в язык.

Сложно, по полезно

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

Регулярные выражения сложно писать, сложно читать и сложно поддерживать/изменять.

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

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

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

Как выглядят регулярные выражения

В JavaScript регулярные выражения это объект, который может быть определён двумя способами.

Первый способ заключается в создании нового объекта RegExp с помощью конструктора:

Второй способ заключается в использовании литералов регулярных выражений:

Вы знаете что в JavaScript есть литералы объектов и литералы массивов? В нём также есть литералы regexp.

В приведённом выше примере hey называется шаблоном. В литеральной форме он находится между двумя слэшами, а в случае с конструктором объекта, нет.

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

Как они работают?

Регулярное выражение, которое мы определили выше как re1 , очень простое. Оно ищет строку hey без каки-либо ограничений: строка может содержать много текста, а слово hey находиться где-то в середине и регулярное выражение сработает. Строка может содержать только слово hey и регулярка опять сработает.

Это довольно просто.

Вы можете попробовать протестировать регулярное выражение с помощью метода RegExp.test(String) , который возвращает логическое ( boolean ) значение:

В примере выше мы просто проверили удовлетворяет ли «hey» шаблону регулярного выражения, который храниться в re1 .

Это проще простого, но вы уже знаете много о регулярных выражениях.

Закрепление

сработает независимо от того где находится hey внутри строки.

Если вы хотите найти строки, которые начинаются с hey , то используйте оператор ^ :

Если вы хотите найти строки, которые заканчиваются на hey , то используйте оператор $ :

Объединяя два предыдущих оператора вы можете найти строку, которая полностью совпадает с hey :

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

Поиск элементов по диапазону

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

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

Диапазоны можно комбинировать:

Поиск многократных совпадений элемента диапазона

Вы можете проверить содержит ли строка только один символ из диапазона с помощью символа — :

Инверсия шаблона

Символ ^ в начале шаблона привязывает его к началу строки.

Использование этого символа внутри диапазона инвертирует диапазон, поэтому:

Метасимволы

  • \d совпадает с любым числом, эквивалентно [0-9]
  • \D совпадает с любым символом, который не является числом, эквивалентно [^0-9]
  • \w совпадает с любым буквенно-числовым символом, эквивалентно [A-Za-z0-9]
  • \W совпадает с любым символом, который не является буквенно-числовым значением, эквивалентно [^A-Za-z0-9]
  • \s совпадает с любым пробельным символом: пробел, табуляция, символ новой строки и пробелы Unicode
  • \S совпадает с любым символом, который не является пробелом
  • \0 совпадает с null
  • \n совпадает с символом новой строки
  • \t совпадает с символом табуляции
  • \uXXXX совпадает с символом Unicode с кодом XXXX (требуется флаг u )
  • . совпадает с любым символовом, кроме символа новой строки (таким как \n ) (если вы не используете флаг s , объясним позже)
  • [^] совпадает с любым символом, включая символ новой строки. Полезно при работе с многострочными строками

Выбор в регулярных выражениях

Если вы хотите выбрать одну или другую строку, используйте оператор | .

Квантификаторы

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

Вы можете использовать квантификатор ? , который сделает этот символ необязательным. В нашем случае цифра должна встречаться 0 или 1 раз:

но что если мы хотим чтобы регулярное выражение срабатывало на несколько цифр?

Вы можете сделать это 4 способами, используя + , * , и .

Совпадает с одним или более (>=1) элементами:

Совпадает с 0 или более (>=0) элементами:

Совпадает точно с n количеством элементов:

Совпадает с диапазоном от n до m элементов:

m можно опустить и оставить второй предел без ограничений, чтобы было минимум n элементов:

Опциональные элементы

Следующий за элементом знак ? , сделает его необязательным:

Группы

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

Пример ниже ищет точное совпадение из 3 цифр за которым следует один или более буквенно-числовые символов:

Повторяющиеся символы, которые находятся после закрывающей группу скобки, относятся ко всей группе:

Захват групп

До сих пор мы видели, как тестировать строки и проверять, содержат ли они определенный шаблон.

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

Вы можете делать это с помощью групп, а точнее с помощью захвата групп.

По умолчанию, группы итак захватываются. Теперь вместо использования RegExp.test(String) , который просто возвращает логическое значение, мы будем использовать один из следующих методов:

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

Если совпадений не найдено, то он возвращает null .

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

Опциональные группы

Захват групп можно сделать опциональным с помощью (. )? . Если ничего не будет найдено, то в возвращаемый массив будет добавлен элемент undefined :

Ссылка на найденную группу

Каждой найденной группе присваивается число. $1 ссылается на первый элемент, $2 на второй, и так далее. Это полезно, когда мы будет говорить о замене части строки.

Именованный захват групп

Это новая возможность ES2020.

Группе можно назначить имя, а не просто слот в возвращаемом массиве:

Использование match и exec без групп

Существует разница при использовании match и exec без групп: в первом элементе массива будет находится не полностью найденная строка, а прямое совпадение:

Незахватываемые группы

Так как по умолчанию группы являются захватываемыми, нам нужен способ игнорировать некоторые группы в возвращаемом массиве. Это возможно с помощью незахватываемых групп, которые начинаются с (. ) .

Флаги

Вы можете использовать следующие флаги на любых регулярных выражениях:

  • g : ищет совпадения глобально
  • i : делает регулярное выражение не чувствительным к регистру
  • m : включает многострочный режим. В этом режиме ^ и $ совпадают с началом и концом всей строки. Без этого флага, с многострочными строками они совпадают с началом и концом каждой строки.
  • u : включает поддержку Unicode (добавлено в ES6/ES2015)
  • s : (новое в ES2020) сокращение от «single line», он позволяет . совпадать с символами новой строки

Флаги можно комбинировать, а также они добавляются в конец строки литерала:

или передаются вторым параметром в конструктор объекта RegExp:

Инспектирование регулярных выражений

Вы можете инспектировать свойства регулярных выражений:

  • source — строка шаблона
  • multiline — принимается значение true если установлен флаг m
  • global — принимается значение true если установлен флаг g
  • ignoreCase — принимается значение true если установлен флаг i
  • lastIndex

Экранирование

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

Границы строк

\b и \B позволяют определить находится ли строка в начале или конце слова:

  • \b совпадает если набор символов находится в начале или конце слова
  • \B совпадает если набор символов не находится в начале или конце слова

Замена с помощью регулярных выражений

Мы уже видели как нужно проверять строки на совпадение с шаблоном.

Также мы видели как можно извлекать часть строк соотвествующие шаблону в массив.

Теперь давайте рассмотрим как заменять части строки на основе шаблона.

У объекта String в JavaScript есть метод replace() , который можно использовать без регулярных выражений для одной замены в строке:

Этот метод также может принимать и регулярное выражение в качестве аргумента:

Использование флага g — это единственный способ заменить несколько вхождений в строке на ванильном JavaScript:

Группы позволяют нам делать больше причудливых вещей, менять местами части строк:

Вместо строки можно использовать функцию, чтобы делать ещё более интересные вещи. В неё будет передан ряд аргументов, таких как возвращают методы String.match(RegExp) или RegExp.exec(String) , где количество аргументов зависит от количества групп:

Жадность

Регулярные выражения называются жадными по умолчанию.

Возьмём например это регулярное выражение:

Предполагается, что нам нужно извлечь из строки сумму в долларах:

но что если у нас есть больше слов после числа, это отвлекает

Почему? Потому что регулярное выражение после знака $ совпадает с любым символом .+ и не останавливается пока не достигнет конца строки. Затем он останавливается, потому что \s? делает конечное пространство необязательным.

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

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

Опережение: соответствие строки в зависимости от того что за ней следует

Используйет ?= для поиска совпадений в строке за которой следует определённая подстрока

?! выполняет обратную операцию и находит совпадений в строке за которыми не следует определённая подстрока:

Ретроспектива: соответствие строки в зависимости от того что ей предшествует

Это новая возможность ES2020.

Опережение использует символ ?= . Ретроспектива использует ? :

Инверсия ретроспективы использует ? :

Регулярные выражения и Unicode

Флаг u является обязательным при работе с Unicode строками, в частности когда может понадобится обрабатывать строки в астральных плоскостях, которые не включены в первые 1600 символов Unicode.

Например эмодзи, но и только они.

Если вы не добавили этот флаг, то это просто регулярное выражение, которые должно найти совпадение одного символа, не будет работать, потому что для JavaScript этот эмодзи внутри представлен двумя символами:

Поэтому, всегда используйте флаг u .

Unicode, как и обычные символы, может обрабатывать диапазоны:

JavaScript проверяет внутренние коды представления, поэтому ? \u1F436 \u1F43A \u1F98A . Посмотрите полный список эмодзи чтобы увидеть коды и узнать их порядок.

Экранирование свойств Unicode

Как мы говорили выше, в шаблоне регулярного выражения вы можете использовать \d чтобы найти совпадение на любую цифру, \s чтобы найти совпадение на любой символ кроме пробела, \w чтобы найти совпадение на любой буквенно-числовой символ и т. д.

Экранирование свойств Unicode — это возможность ES2020, которая добавляет очень крутую функцию, расширяя эту концепцию на всех Unicode символы и добавляя \p<> и \P<> .

У любого Unicode символа есть набор свойств. Например Script определяет семейство языков, ASCII — это логическое значение равное true для ASCII символов и т.д. Вы можете положить это свойство в фигурные скобки и регулярное выражение будет проверять чтобы его значение было истинным:

ASCII_Hex_Digit — это ещё одно логическое свойство, которое проверяет содержит ли строка тольк валидные шестнадцатеричные цифры:

Существует много других логических свойств, которые вы можете проверить просто добавив их имя в фигурные скобки, включая Uppercase , Lowercase , White_Space , Alphabetic , Emoji и другие:

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

Прочитать больше обо всех свойствах вы можете здесь.

Примеры

Извлечение числа из строки

Предположим, что есть строка содержащая только одно число, которое нужно извлечь. /\d+/ должен сделать это:

Поиск E-mail адреса:

Простейший подход заключается в проверке безпробельных символов до и после знака @ , с помощью \S :

Однако, это упрощенный пример, так как под него попадает множество не валидных E-mail адресов.

Захват текста между двойными кавычками

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

Лучший способ сделать это — использовать захват групп, потому то мы знаем что наше совпадение должно начинаться и заканчиваться символом » , поэтому мы можем легко настроить шаблон, но также мы хотим удалить эти кавычки из результата.

Мы найдём то что нам нужно в result[1] :

Получение содержимого из HTML тега

Например получить содержимое из тега span , допуская при этом любое количество аргументов у тега:

Учебник: Регулярные выражения (regular expressions)

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

  • Вы пишете программу, в которой обрабатываются номера телефонов, допустим в формате +7(ххх)ххх-хх-хх. Возможно их надо найти в тексте, а может быть — проверить корректность. На месте номеров могли бы быть номер банковской карты, IP-адрес, электронная почта, ФИО (в формате Петров А.Ю.), да и вообще что угодно.
  • В Microsoft Word при поиске и замене можно включить режим поддержки регулярных выражений поставив галочку напротив пункта «подстановочные знаки». Потом можно искать все то, что указано в первом пункте, но программу писать не требуется. И заменять можно. В LibreOffice/OpenOffice это тоже поддерживается.
  • Естественно, регулярные выражения поддерживаются во всех современных средах разработки — Qt Creator, Microsoft Visual Studio, NetBeans, IntelliJ IDEA и даже блокнотах — Notepad++, kate, gedit и др. Вы пишете код и решили что-то переименовать, да как-то особенно…

Остается научиться всем этим пользоваться. Значительную часть описанных ниже примеров можно проверить в том же Notepad++ или Microsoft Word. Для других (связанных с программированием) — можно использовать сервис regex101, он удобен не только для обучения, но и для реальной разработки.

Содержание:

1 Теоретический раздел

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

1.1 Одиночные символы

Символ «точка» (.) заменяет в регулярных выражениях любой символ. Так, например, если в тексте есть слова «порог» и «пирог» — то выражение «п.рог» будет удовлетворять обоим из них. Ниже приведен пример такого поиска в тектовом редакторе kate, остальные примеры будут даваться без скриншотов.

Если же нас интересуют не все варианты замены символа — используется представление с квадратными скобками. В скобках перечисляются альтернативные символы. Также, в квадратных скобках можно задавать диапазоны символов с помощью «тире». Ниже приведена схема для выражения «var_[a-d][123]», можно попробовать выписать строки, которое оно описывает:

Если символ «тире» должен являться частью перечисления — его нужно ставить первым или последним. Например, в таком выражении:

ставить тире между «+» и «*» нельзя, так как это будет интерпретировано как диапазон.

Также с помощью перечислений можно искать «все символы кроме», для этого первым символом перечисления должен быть «^» . Так, чтобы найти в тексте все символы кроме «ё» , «й» и символов «a-z» можно использовать такое выражение: «[^ёйa-z]» .

Если символ «^» стоит вне квадратных скобок — то он задает начало строки (до сих пор поиск осуществлялся во всем тексте). Символ «$» соответствует концу строки.

Если вдруг вам нужно найти в тексте какой-либо из «управляющих символов» — то его нужно экранировать с помощтю слеша. Так, например, символы «^» , «[» в регулярном выражении должны быть заменены на «\^» , «\[» . На практике часто приходится искать символ слеша, который также является управляющим и заменяется на «\\» .

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

Выражение Символ
«\d» цифра
«\D» все кроме цифры «[^0-9]»
«\s» пробельный символ (табуляции, пробелы)
«\S» все, кроме пробельных символов
«\w» буква (любой язык, в любом регистре)
«\W» все кроме букв
«\b» граница слова
«\B» не граница слова

Такие обозначения могут использоваться в качестве элементов перечисления, например «[\d\w]» соответствует букве или цифре.

1.2 Квантификация

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

Выражение Количество повторений
«*» 0 или более раз
«+» 1 или более раз
«?» 0 или 1 раз
«« точно n раз
«« от n до m раз

С помощью кванторов мы можем описать, например строку, содержащую номер банковской карты:

Под такое описание подойдут, например, строки «1234-1234-1234-1234» и «12345678 12345678» .

1.3 группировка (подвыражения)

Выражение может состоять из подвыражений, заключенных в круглые скобки. Для программиста это очень важно, так как к подвыражению можно обратиться по индексу. Кроме того, подвыражения используются для задания альтернатив, которые можно перечислять с помощью вертикальной черты. Так, например, следующее выражение соответствует строкам «+7 902», «8(902)» и еще множеству вариантов:

Тут «\(» используется для экранирования скобок. Подвыражения на практике применяются очень часто, но нам не всегда нужна возможность получить подстроку, соответствующую подвыражению. При выборе подстрок в коде вашей программы «лишние» подвыражения мешают, из-за них «съезжают» индексы, исправить ситуацию можно с использованием следующего синтаксиса: «(?:pattern)» . Кроме того, такая форма записи более эффективна, т.к. сохраняет меньше данных.

Также, с группами связано так называемое «заглядывание вперед» — это нечасто применяемая на практике техника позволяет проверить соответствие подвыражению, не смещая позицию поиска и не запоминая найденное соответствие. Синтаксис используется следующий «(?=pattern)» . Пусть дан следующий файл со списком языков программирования:

мы ожидаемо получим три строки, однако что если, к уже найденному подвыражению требуется применить какие-то дополнительные «фильтры»? То есть, после этой проверки мы хотим еще раз проверить названия языков. Сделать это можно заменив «?:» на «?=» .

Теперь будут получены только две строки — Lua и Lisp, а второе подвыражение «(.*)» будет сопоставлено с типами соответствующих языков.

Негативное заглядывания вперед ищет несоответствие строки шаблону «(?!pattern)» . Такое выражение выбирает подстроки, не соответствующие «pattern» без запоминания подстроки и не смещая текущую позицию поиска. Так, для рассмотренного выше примера, такой тип заглядывания вернет единственную строку с языком Logo. Первое подвыражение выберет строки с языками Basic, Prolog, С++ и Logo, а второе — оставит из них только те, чьи названия начинаются с символа «L» .

1.4 Что есть еще?

Наряду с заглядыванием вперед, в некоторых реализациях поддерживается позитивное и негативное заглядывания назад — «(? и «(? , соответственно. Полезно знать, что нечто подобное существует, чтобы в случае чего — найти в справочнике и применить.

Описанное выше должно одинаково работать в любой среде, поддерживающей регулярные выражения, однако в отдельных реализациях доступно больше возможностей или синтаксис выражений может незначительно отличаться. С помощью регулярных выражений можно искать строки в тексте, однако в каком регистре выполняется поиск? — ответ зависит от реализации. Управлять регистром можно с помощью модификаторов : «(?i)» включает чувствительность к регистру, а «(?-i)» — выключает ее. Существуют и другие модификаторы, но они используются реже. Работа модификаторов зависит от реализации. Некоторые реализации поддерживают также флаги, которыми также можно управлять регистром.

Ряд реализаций поддерживает очень удобный поиск по условию: «(?(?=если)то|иначе)» . Нечто подобное позволяет реализовать «просмотр вперед». «Если» условие выполнится — будет выполнено сопоставление с «то», в противном случае — с «иначе». Сопоставление в данном случае создает группу, к которой можно обратиться по индексу из вашего кода.

2 Практический раздел. Ссылки

Перед тем, как использовать регулярные выражения, стоит посмотреть в документацию по вашему языку программирования и используемой библиотеке, так как диалекты обладают особенностями. Например в Perl и некоторых версиях php можно описывать рекурсивные регулярные выражения, которые не поддерживаются большинством других реализаций; механизмом флагов отличается JavaScript и так далее. Незначительными отличиями могут обладать даже различные версии одной и той же библиотеки.

Отличаются регулярные выражения не только синтаксисом, но и реализацией. Регулярные выражения — это «не просто так». Строка, задающее выражение, преобразуется в автомат, от реализации которого зависит эффективность. Масштаб проблемы хорошо иллюстрирует график зависимости времени выполнения поиска от длины строки и реализации:

Картинка взята из статьи «Поиск с помощью регулярных выражений может быть простым и быстрым«. В ней можно прочитать про различные реализации выражений, а также о том, как написать выражение так, чтобы оно работало быстрее. Кстати, так как выражение преобразуется в автомат, то зачастую его удобно визуализировать — для этого есть специальные сервисы, например. Для последнего выражения статьи будет построен такой автомат:

Примеры использования регулярных выражений:

  • для валидации вводимых в поля данных: QVal >javax.faces.validator.Validator ;
  • для парсинга сайтов: Парсер сайта на Qt, использование QRegExp. В примере с сайта-галереи выбираются и скачиваются картинки заданных категорий;
  • для валидации данных, передаваемых в формате JSON ряд библиотек позволяет задавать схему. При этом для строковых полей могут быть заданы регулярные выражения. В качестве упражнения можно попробовать составить выражение для пароля — проверить что строка содержит символы в разном регистре и цифры.

В сообществе Программирование и алгоритмы можно посмотреть дополнительную литературу по теме. Книгу Гойвертса и Левитана рекомендую посмотреть особенно, так как в ней по-полочкам разобраны десятки примеров, причем с учетом специфики реализации регулярных выражений в конкретных языках программирования.

Регулярные выражения для чайников

Что такое регулярные выражения?

В народе: регэкспы, регулярки.

По-простому — это выражения для поиска и замены подстроки по шаблону.

В PHP используется название PCRE (Perl Compatible Regular Expressions —
перл совместимые регулярные выражения). В этой статье я постараюсь раскрыть
потенциал это мощного инструмента программиста. Не пытайтесь понять все сразу,
впитывайте порциями и приходите за добавкой.

Начнем

// наша строка для испытаний
$string = ‘abcdefghijklmnopqrstuvwxyz0123456789’ ;

Если нам нужно просто узнать есть ли шаблон ‘abc’ в строке $string
мы можем набросать такой код:

echo preg_match ( «/abc/» , $string ) ;
?>

Этот код выведет ‘1’. Потому что он нашел 1 (одно) вхождение шаблона в строке.
Если шаблон в строке не обнаружен, preg_match вернет 0. При нахождении первого вхождения,
функция сразу возвращает результат! Дальнейший поиск не продолжается (см. preg_match_all)

Нахождение начала строки

Теперь мы желаем узнать, начинается ли строка с ‘abc’.
Символ начала строки в регулярках — ‘^’ (caret — знак вставки).

// тест на начало строки
if ( preg_match ( «/^abc/» , $string ) )
<
// окей, строка начинается с абс
echo ‘The string begins with abc’ ;
>
else
<
echo ‘это фэйл’ ;
>
?>

Пример выведет:
The string begins with abc

Оборачивающие слэши — разделители, содержат регуряное выражение. Это могут быть любые парные символы,
например @regex@, #regex#, /regex/ и .т.п.

Символ ^ сразу после первого разделителя указывает что выражение начинается сначала строки и НИКАК иначе.

Что делать с регистром символов (строчные-прописные)

Перепишем код, чтобы он искал строку ‘ABC’:

Скрипт вернет:
Не думаю

Все потому что поиск регистро-зависимый. Шаблон ‘abc’ не тоже самое что ‘ABC’.
Чтобы найти оба варианта, нужно использовать модификатор. В регулярных выражениях
для этого применяется модификатор ‘i’, который нужно указать за закрывающим разделителем
регулярного выражения.

if ( preg_match ( «/^ABC/i» , $string ) ) <
echo ‘Совпадение, строка начинается с abc’ ;
> else <
echo ‘Не думаю’ ;
>
?>

Теперь скрипт найдет паттерн ‘abc’. Также теперь будут попадать под шаблон
строки вида abc, ABC, Abc, aBc, и т.п.

Позже будет рассказано подробнее о модификаторах.

Как указать в паттерне конец строки

Делается это также как и в случае с поиском начала строки.
Распространенная ошибка, допускаемя многими прогерами — использование символа $ для указания конца строки в шаблоне.
Это неверно, правильное решение — использовать утверждение \z. Посмотрите на этот код

Сниппет вернет true, потому что $ = \Z, что в свою очередь можно описать выражением (?=\z|\n\z).
Когда нам нужно получить в результате строку без «разделителей строк», $ не должен использоваться.
Также $ совпададет больше одного раза с модификатором /m, в противоположность \z. Изменим немного код,
удалим каретку (^) в начале паттерна и добавим \z в конце, также уберем зависимость от регистра модификатором /i.

// паттерн в конце строки?
if ( preg_match ( «/89 \z /i» , $string ) ) <
echo ‘Совпадение, строка заканчивается на 89’ ;
> else <
echo ‘Не думаю’ ;
>
?>

Результат скрипта:
>> Совпадение, строка заканчивается на 89

Потому что мы определили конец строки 89. Вот так.

Мета символы

Ранее мы поэкспериментировали с простыми регулярками. Познакомились с кареткой (^) и долларом ($)/
Эти символы имееют особенное значение. Каретка (^) обозначает начало страки и доллар ($) — ее конец.
Такие символы в купе с остальными специальными называются мета символами (meta characters).

Список мета символов в регулярных выражениях:

Разберем все символы на примерах.
Если вам нужно составить шаблон в котором содержится такой символ, его необходимо экранировать (см. preg_quote)
Например шаблон: «1+1», нужно записать как-то так:

// образец
$string = ‘1+1=2’ ;

if ( preg_match ( «/^1 \+ 1/i» , $string ) ) <
// yep
echo ‘The string begins with 1+1’ ;
> else <
// nope
echo ‘Не думаю’ ;
>
?>

Результат скрипта:
The string begins with 1+1

Потому что интерпретатор проигнорировал специальное значение символа «+», обозначенного символом экранирования «\» (бэкслэш).
Если бы мы не добавили экран к плюсу, то preg_match(«/^1+1/i», $string) не нашло бы совпадений с шаблоном.
Сам бэкслэш в свою очередь тоже нужно экранировать, если мы ищем именно этот символ «\\».

Что означают остальные мета символы

Квадратные скобки [ ] обозначают «строковой класс».

Символьный класс. Это просто набор символов, которые должны совпасть в искомой строке.
Они могут записываться индивидуально (по одному):

Или как диапазон, разделенный символом «-«:

// Ищем шаблон
echo preg_match ( «/b[aoiu]g/» , $string , $matches ) ;

Результат скрипта:
return 1

Потому что preg_match() нашел совпадение.
Этот код также найдет совпадение со строками ‘bag’ ‘bog’ ‘big’, но не с ‘beg’.
Диапазон символов [a-f] равнозначен такой записи [abcdef]. Словами формулируется так [от ‘a’ до ‘f’].
Еще раз повторю, выражения регистрозависимые, и [A-F] не тоже самое что и [a-f].

Мета символы не работыют внутри классов, поэтому их не нужно экранировать внутри квадратных скобок [. ].
Например класс [abcdef$] совпадет с символами a b c d e f $. Доллар ($) внутри класса — это простой бакс знак доллара без какого либо специального мета-свойства.

Есть правда исключения из правил:
Одна из полезных функций регулярных выражений — возможность указать шаблон НЕ совпадающий с диапазоном символов.
Чтобы это сделать, нужно использовать каретку (^) первым символом класса.
Найдем любые символы, кроме «b»:

// осуществляем поиск
preg_match ( «/[^b]/» , $string , $matches ) ;

// выведем все совпадения в цикле foreach
foreach ( $matches as $key => $value ) <
echo $key . ‘ -> ‘ . $value ;
>
?>

Результат скрипта:
0 -> a

Здесь preg_match() нашел первое совпадение с шаблоном /[^b]/.
Изменим скрипт и используем preg_match_all() для нахождения всех вхождений соответствующих шаблону /[^b]/.

// ищем ВСЕ совпадения
preg_match_all ( «/[^b]/» , $string , $matches ) ;

// выведем все совпадения в цикле foreach
foreach ( $matches [ 0 ] as $value ) <
echo $value ;
>
?>

Результат скрипта:
acefghijklmnopqrstuvwxyz0123456789

Выведет все символы, которые НЕ совпадают с шаблоном «b».

Так мы можем отфильтровать все цифры в строке:

// все символы не являющиеся цифрами от 0 до 9
preg_match_all ( «/[^0-9]/» , $string , $matches ) ;

foreach ( $matches [ 0 ] as $value ) <
echo $value ;
>
?>

Результат скрипта:
abcefghijklmnopqrstuvwxyz

Шаблон [^0-9] расшифровывается как все НЕ включая цифры от 0 до 9.

Продолжаете слушать нашу радиостанцию?
Тогда продолжим.

Метасимвол Бэкслэш (\).

Основное значение — экранирование других метасимволов.

// create a string
$string = ‘This is a [templateVar]’ ;

// try to match our pattern
preg_match_all ( «/[ \[ \] ]/» , $string , $matches ) ;

// loop through the matches with foreach
foreach ( $matches [ 0 ] as $value ) <
echo $value ;
>
?>

Здесь мы хотели найти все символы []. Без экранирования шаблон выглядел бы так — «/[[]]/»,
но мы добавили бэеслэши к скобкам [], чтобы отменить их мета-статус.
Также, к примеру, поступим с путем к файлу.
c:\dir\file.php
В паттерне будем использовать разделитель «\\».

Бэкслэш также ортодоксально используется в строках для указания специальных последовательностей: \n, \r и др.

Еще он неймспейсы разделяет!

Следующий символ «.» (точка) ака «полный стоп».

`Точка` совпадает с любым символом кроме символов разрыва строки \r или \n.
С помощью точки мы можем найти любой одиночный символ, за исключением разрыва строки.
Чтобы точка также совпадала с переводом каретки и разрывом строки, можно использовать флаг /s.

Ищем одиночный символ

$string = ‘sex at noon taxes’ ;

echo preg_match ( «/s.x/» , $string , $matches ) ;
?>

Результат скрипта:
1

Да, да preg_match() нашел одно совпадение. Пример также сработает с sax, six, sox, sux, и s x, но не совпадет с «stix».

Теперь попробуем найти \n.

// create a string
$string = ‘sex’ . » \n » . ‘at’ . » \n » . ‘noon’ . » \n » . ‘taxes’ . » \n » ;

// echo the string
echo nl2br ( $string ) ;

// look for a match
echo preg_match_all ( «/ \s /» , $string , $matches ) ;

Результат скрипта:
sex
at
noon
taxes
4

preg_match_all() нашел 4 совпадения разрыва строки «\n» потому что мы использовали флаг \s. Подробнее про флаге в разделе Спец Последовательностей..

Следующий волшебный символ — звездочка (*) asterisk
Совпадает с НОЛем и/или БОЛЕЕ вхождений шаблона, находящегося перед звездочкой.
* означает опциональный шаблон — допускается что символы могут быть, а могут и отсутствовать в строке.
Так шаблон .* совпадает с любым количеством любых символов. Пример:

// create a string
$string = ‘php’ ;

// look for a match
echo preg_match ( «/ph*p/» , $string , $matches ) ;

Результат скрипта:
1

Нашлось одно совпадение. В примере это один символ «h».
Пример также совпадет также со строкой «pp» (ноль символов «h»), и «phhhp» (три символа «h»).

Добрались до мета символа символа «+»

Плюс почти тоже самое что и звездочка, за исключением того что плюс совпадает с ОДНИМ и БОЛЬШЕ символом.
Так в примере звездочка «*» совпала со строкой ‘pp’, с плюсом «+» такое не пройдет.

// create a string
$string = ‘pp’ ;

// look for a match
echo preg_match ( «/ph+p/» , $string , $matches ) ;

Результат скрипта:

Потому что ни одного символа «h».

Следубщий пациент
Мета символ «?»

Знак вопроса совпадет с НУЛЕМ или ОДНИМ вхождением символа или регулярным выражением,
указанным сразу перед ним. Полезен для указания опциональных символов (которых может и не быть).

Например, телефонный номер в Австралии: 1234-5678.

// create a string
$string = ‘12345678’ ;

// look for a match
echo preg_match ( «/1234-?5678/» , $string , $matches ) ;

Результат скрипта:
1

Потому что -? совпал 0 раз с символом «-«. Изменение строки на «1234-5678» выдаст тот же результат.

Фигурные скобки <>

Указывает на количество совпавших символов или их интервал.
Например, за фразой PHP должно следовать ТОЧНО ТРИ цифры:

// create a string
$string = ‘PHP123’ ;

// look for a match
echo preg_match ( «/PHP[0-9]<3>/» , $string , $matches ) ;

Результат скрипта:
1

Шаблон PHP 0-9(цифры от 0 до 9) <3>(три раза) совпал.

Специальные последовательности

Бэкслэш (\) используется для спец. последовательностей:

* \d — любая цифра (тоже самое что и [0-9])
* \D — любая НЕ цифра ([^0-9])
* \s — все «недосимволы» — пробелы, переводы строки, табуляция ([ \t\n\r\f\v])
* \S — все НЕ «недосимволы» ([^ \t\n\r\f\v])
* \w — все альфа-цифровые символы (буквенно-числовые) ([a-zA-Z0-9_])
* \W — все НЕ альфа-цифровые символы ([^a-zA-Z0-9_])

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

// match our pattern containing a special sequence
preg_match_all ( «/[ \w ]/» , $string , $matches ) ;

// loop through the matches with foreach
foreach ( $matches [ 0 ] as $value ) <
echo $value ;
>
?>

Результат скрипта:
abcefghijklmnopqrstuvwxyz0123456789

Мы нашли (preg_match_all) все цифры и буквы (\w) класса ( [] ).

На следующем примере мы можем убедиться, что строка не содержит чисел.

// create a string
$string = ‘2 bad for perl’ ;

// echo our string
if ( preg_match ( «/^ \d /» , $string ) ) <
echo ‘String begins with a number’ ;
> else <
echo ‘String does not begin with a number’ ;
>
?>

Метасимвол «.» (Точка, полный стоп)

Совпадает один раз с любым символом (кроме разрыва строки)

// create a string
$string = ‘abcdefghijklmnopqrstuvwxyz0123456789’ ;

// try to match any character
if ( preg_match ( «/./» , $string ) ) <
echo ‘The string contains at least on character’ ;
> else <
echo ‘String does not contain anything’ ;
>
?>

Результат скрипта:
The string contains at least on character

Конечно, код содержит хотябы один символ.

Ранее была рассмотрена проблема нахождения символа разрыва строки, потому что «.» не совпадает с таким символом (\n).
Здесь нам на помощь придет флаг \s. Он найдет любой пробельный символ (недосимвол).

Для примера используем \n.

// create a string
$string = ‘sex’ . » \n » . ‘at’ . » \n » . ‘noon’ . » \n » . ‘taxes’ . » \n » ;

// echo the string
echo nl2br ( $string ) ;

// look for a match
echo preg_match_all ( «/ \s /» , $string , $matches ) ;

Результат скрипта:
sex
at
noon
taxes
4

preg_match() нашел 4 совпадения перевода строки \n.

Теперь все вместе, хором

Более сложные выражения.
Рассмотрим оператор OR (ИЛИ).
В регулярных выражениях это символ «|» (труба, канал).

Настало время показательного «Hello World» скрипта.

// a simple string
$string = «This is a Hello World script» ;

// try to match the patterns This OR That OR There
echo preg_match ( «/^(This|That|There)/» , $string ) ;
?>

Усложним задачу: попытаемся найти одновременно Hello или Jello в строке.

// a simple string
$string = «This is a Hello World script» ;

// try to match the patterns Jello or Hello
if ( ! preg_match ( «/(Je|He)llo/» , $string ) ) <
echo ‘Pattern not found’ ;
> else <
echo ‘pattern found’ ;
>
?>

Хотя шаблон совпал, мы не видим какую имеено сроку мы нашли.
Для возвращения найденных результатов в preg_match добавляется третий параметр (&$matches):

// a simple string
$string = «This is a Hello World script» ;

// try to match the patterns Jello or Hello
// put the matches in a variable called matches
preg_match ( «/(Je|He)llo/» , $string , $matches ) ;

// loop through the array of matches and print them
foreach ( $matches as $key => $value ) <
echo $key . ‘->’ . $value . ‘
‘ ;
>
?>

Элемент массив $matches[0] содержит всю совпавшую подстроку (всегда), в примере — Hello.
Последующие элементы содержат последовательно вхождения субпаттернов «()».
$matches[1] совпадает с первым субпатерном. В примере — (Je|He)

Модификаторы и утверждения

Модификаторы изменяют поведения шаблонов регулярных выражений.

i — регистронезависимый (Ignore Case, case insensitive)
U — нежадный поиск (Make search ungreedy)
s — включая перевод строки (Includes New line)
m — мультистрока (Multiple lines)
x — Extended for comments and whitespace
e — Enables evaluation of replacement as PHP code. (preg_replace only)
S — Extra analysis of pattern

b — граница слова (Word Boundry)
B — НЕ граница слова (Not a word boundary)
A — начало шаблона (Start of subject)
Z — конец шаблона или разрыв строки (End of subject or newline at end)
z — конец шаблона (End of subject)
G — первая совпавшая позиция в шаблоне (First matching position in subject)
?>

Простой пример модификатора «i»

// create a string
$string = ‘abcdefghijklmnopqrstuvwxyz0123456789’ ;

// try to match our pattern
if ( preg_match ( «/^ABC/i» , $string ) ) <
echo ‘Совпадение, строка начинается с abc’ ;
> else <
echo ‘Не думаю’ ;
>
?>
?>

Использование модификатора «s»

/*** create a string with new line characters ***/
$string = ‘sex’ . » \n » . ‘at’ . » \n » . ‘noon’ . » \n » . ‘taxes’ . » \n » ;

/*** look for a match */
echo preg_match ( «/sex.at.noon/» , $string , $matches ) ;

Результат скрипта:

«.» не находит символы разрыва строки, добавим модификатор «s»
чтобы это исправить

/*** create a string with new line characters ***/
$string = ‘sex’ . » \n » . ‘at’ . » \n » . ‘noon’ . » \n » . ‘taxes’ . » \n » ;

/*** look for a match using s modifier ***/
echo preg_match ( «/sex.at.noon/s» , $string , $matches ) ;
?>
?>

Результат скрипта:
1

Разрывы строк позволяют нам использовать модификатор «m».
Это улично-магический модификатор. Он принимает строку за однострочнкую с символом разрыва на конце,
даже если в строке на самом деле больше символов разрыва (мультистрока).
Т.е. если в строке нет символов разрыва строк, этот модификатор ничего не значит.

// create a string
$string = ‘sex’ . » \n » . ‘at’ . » \n » . ‘noon’ . » \n » . ‘taxes’ . » \n » ;

// look for a match
if ( preg_match ( «/^noon/im» , $string ) ) <
echo ‘Pattern Found’ ;
> else <
echo ‘Pattern not found’ ;
>
?>

Результат скрипта:
Pattern Found

Конечно регулярное выражение найдет совпадение.
Все что следует после первого символа разрыва строки отбрасывается из-за модификатора «m».

В примере используюся вместе модификаторы «i» и «m», их действие комбинируется.

«x» модификатор позволяет составлять регулярное выражение на нескольких строках,
что повышает его читабельность и позволяет добавлять комментарии внутри шаблона.

// create a string
$string = ‘sex’ . » \n » . ‘at’ . » \n » . ‘noon’ . » \n » . ‘taxes’ . » \n » ;

// create our regex using comments and store the regex
// in a variable to be used with preg_match
$regex = ‘
/ # opening double quote
^ # caret means beginning of the string
noon # the pattern to match
/imx
‘ ;

// look for a match
if ( preg_match ( $regex , $string ) ) <
echo ‘Pattern Found’ ;
> else <
echo ‘Pattern not found’ ;
>
?>

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

Модификатор «e»

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

Модификатор «S»

Этот модификатор позволяет нам проанализировать строку до сопостовления с шаблонами,
которые не помечены якорями. Т.е. если шаблон не имеет начальной фиксированой позиции, как например:

Паттерн может успорить выполение шаблона в случае с множественными совпадениями.
В следующем примере появляется множественное вхождение шаблона, поэтому добавим «S».

// match our pattern containing a special sequence
preg_match_all ( «/[ \w ]/S» , $string , $matches ) ;

// loop through the matches with foreach
foreach ( $matches [ 0 ] as $value ) <
echo $value ;
>
?>

Результат скрипта:
abcefghijklmnopqrstuvwxyz01234567890

На практике модификатор используется достаточно редко.

Модификатор границы слова (word boundary) «\b»

Граница слова создается между двух «\b» модификаторов.
Это специальный «подпирающий тип модификаторов, которые позволяют указть ТОЧНОЕ совпадение.
Текст должен совпасть только с точным шаблоном заключенным в «\b»
Например, шаблон «cat» не совпадет с «catalog».

$string = ‘eregi will not be available in PHP 6’ ;

// ищем строку «lab»
if ( preg_match ( «/ \b lab \b /i» , $string ) ) <
// Совпадение
echo $string ;
> else <
echo ‘Не думаю’ ;
>
?>

Результат скрипта:
Не думаю

Мы пытаемся найти совпадение с паттерном «lab», которое находится внутри строки в слове «available».
Из за использования границ слов, шаблон не совпал с подстрокой.
Давайте попробуем пример, не используя модификатора границ слов.

$string = ‘eregi will remain in the computer lab’ ;

// ищем строку «lab»
if ( preg_match ( «/ \b lab \b /i» , $string ) ) <
// Совпадение
echo $string ;
> else <
echo ‘Не думаю’ ;
>
?>

Результат скрипта:
eregi will remain in the computer lab

Мы видим что совпадение произошло с целым словом «lab». (\blab\b).

Модификатор \B

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

$string = ‘This lathe turns wood.’ ;

// match word boundary and non-word boundary
if ( preg_match ( «/ \B the \b /» , $string ) ) <
echo ‘Совпал шаблон «the».’ ;
> else <
echo ‘Не думаю’ ;
>
?>

Результат скрипта:
>> Совпал шаблон «the».

Этот код сначала найдет паттерн «the». Потому что сначала указан модификатор «не граница слова»,
the находится внутри фразы и не снача ее, затем модификатор \b границы указывает что фраза должна
закончится на -the.

$string = ‘The quick brown fox jumps over the lazy dog.’ ;

// match word boundary and non-word boundary
if ( preg_match ( «/ \B the \b /» , $string ) ) <
echo ‘Совпал шаблон «the».’ ;
> else <
echo ‘Не думаю’ ;
>
?>

Результат скрипта:
Не думаю

В этот раз мы ничего не нашли, потому что «the» стоит на границе слова, а мы использовали модификатор \B.

Последний модификатор — \U

По умолчанию, PCRE «жадный» — это не значит что они съедят вашу печеньку,
а означает что шаблон совпадет с наибольшим возможным количеством символов,
попадающих под этот шаблон.

Чтобы отключить такую «жадность» регулярных выражений
— используем ограничитель «?», например «(.*?)»
— используем модификатор «\U».

Новичкам желательно использовать этот модификатор по-умолчанию, чтобы не возникало конфузов.

$string = ‘foobar foo—bar fubar’ ;

// try to match the pattern
if ( preg_match ( «/foo(.*)bar/U» , $string ) ) <
echo ‘Совпадение’ ;
> else <
echo ‘Не думаю’ ;
>

Результат скрипта:
Совпадение

Другой пример — дан кусок html

Попытаемся найти все ссылки выражением preg_match_all(«/.*/s», $string),
код вернет всю искомую строку вместо трех ссылок. Добавив Нежадный модификатор, все три ссылки поотдельности.

Вычисление с preg_replace

Приветствуем на сцене модификатор «e».

Этот модификатор вычисляет заменяемый аргумент.
До этого мы не рассматривали preg_replace(), поэтому быстрый пример:

$string = ‘We will replace the word foo’ ;

// заменяем `for` на `bar`
$string = preg_replace ( «/foo/» , ‘bar’ , $string ) ;

Пример заменит в строке foo на bar. В таких простых заменах целесообразнее использовать функции обработки строк
str_replace(), которые быстрее справляются с простыми задачами, но имеют некоторые ограничения, например не поддерживают юникод.

// строка с шаблонными переменными
$string = ‘This is the <_foo_>bought to you by <_bar_>‘ ;

// создади массив со значениями переменных
$templateVars = [ «FOO» => «The PHP Way» , «BAR» => «PHPro.orG» ] ;

// заменяем и вычисляем
$string = preg_replace ( «/<_(.*?)_>/ime» , » \$ templateVars[‘$1’]» , $string ) ;

Без модификатора «е» скрипты выдаст результат:
This is a $template_vars[FOO] and this is a $template_vars[BAR]

С модификатором переменные вычислятся после замены:
This is the The PHP Way bought to you by PHPro.orG

Таким образом, модификатор «e» обладает потенциалом встроенного шаблонизатора.

Заглядывание вперед (Look Aheads)

Возможность регулярных выражений «заглянуть вперед» шаблона для определения дальнейших совпадений.
«Подглядывание вперед» бывает положительное и отрицательное

Рассмотрим сначала заглядывание вперед с отрицанием. Обозначается в шаблоне символами «?!».
Полезно при поиске шаблона, стоящего впереди от совпадения, которое нам нужно.

$string = ‘I live in the whitehouse’ ;

// try to match white not followed by house
if ( preg_match ( «/white+(?!house)/i» , $string ) ) <
// if we find the word white, not followed by house
echo ‘Совпадение’ ;
> else <
echo ‘Не думаю’ ;
>
?>

Результат скрипта:
No match is found

Потому что слово «white» следует за словом «house».
Подадим блюдо под другим соусом:

$string = ‘I live in the white house’ ;

// try to match white not followed by house
if ( preg_match ( «/white+(?!house)/i» , $string ) ) <
// if we find the word white, not followed by house
echo ‘Совпадение’ ;
> else <
echo ‘Не думаю’ ;
>
?>

Результат скрипта:
Совпадение

Есть совпадение, потому что слово «white» не следует сразу же за словом «house» (как в «whitehouse»)

Позитивное/положительное заглядывание вперед «?=»

$string = ‘This is an example eg: foo’ ;

// try to match eg followed by a colon
if ( preg_match ( «/eg+(?=:)/» , $string , $match ) ) <
print_r ( $match ) ;
> else <
echo ‘Нет совпадений’ ;
>
?>

Результат скрипта:
Array < [0]=>‘eg’ >

Код ищет паттерн «eg», стоящий перед «:» двоеточием.
Но что если нам нужно найти что-то до двоеточия, например дом из предудыщего примера.
Для этого на помощь приходят «заглядывания назад».

Заглядывание назад (Look Behinds)

Позволяет просмотреть строку назад и определить наличие совпадений с шаблоном.
Также разделяется на положительное и отрицательное.
Положительное — записывается «?

$string = ‘I live in the whitehouse’ ;

// try to match house preceded by white
if ( preg_match ( «/(? , $string ) ) <
// if we find the word white, not followed by house
echo ‘Совпадение’ ;
> else <
echo ‘Не думаю’ ;
>
?>

Результат скрипта:
Совпадение

Здесь мы нашли совпадение, потому что паттерн «house» сразу следует за паттерном «house».
Движок регулярных выражений «посмотрел назад» шаблона «house» и определил совпадение.

Если мы хотим, чтобы «house» НЕ следовал за словом «white»?
Используем отрицительное заглядывание назад — «?

/*** a simple string ***/
$string = ‘I live in the whitehouse’ ;

/*** try to match house preceded by white ***/
if ( preg_match ( «/(? , $string ) )
<
/*** if we find the word white, not followed by house ***/
echo ‘Совпадение’ ;
>
else
<
/*** if no match is found ***/
echo ‘Не думаю’ ;
>
?>

Результат скрипта:
no match is found

Потому что отрицательное заглядывание не нашло шаблона «house» c шаблоном «white» в начале его.
Давайте поменяем цвет «дома», белым слишком девственный для правительственного здания.

$string = ‘I live in the bluehouse’ ;

// ищем `house` с непредшествующим `white`
if ( preg_match ( «/(? , $string ) ) <
/*** if we find the word white, not followed by house ***/
echo ‘Совпадение’ ;
> else <
/*** if no match is found ***/
echo ‘Не думаю’ ;
>
?>

Мы изменили «whitehouse» на «bluehouse» и теперь наша регулярка сработала, потому что
шаблон «white» не обнаружен перед «house».

По-умолчанию регулярки жадные, это значит что квантификаторы (какое слово страшное)
*, +, ? «пожирают» столько символов сколько могут.

/*** 4 x and 4 z chars ***/
$string = «xxxxzzzz» ;

/*** greedy regex ***/
preg_match ( «/^(.*)(z+)$/» , $string , $matches ) ;

/*** results ***/
echo $matches [ 1 ] ;
echo «
» ;
echo $matches [ 2 ] ;
?>

Первый паттерн (.*) совпал со всеми четыремя «x» и тремя из четырех символов «z».
Сработала жадность — шаблон забрал столько символов, сколько было в искомой строке.
Проще простого помочь перестать квантификаторам быть жадными, добавив «?» к квантификатору как в примере:

/*** string of characters ***/
$string = «xxxxzzzz» ;

/*** a non greedy match ***/
preg_match ( «/^(.*?)(z+)$/» , $string , $matches ) ;

/*** show the matches ***/
echo $matches [ 1 ] ;
echo «
» ;
echo $matches [ 2 ] ;
?>

Теперь $matches[1] содержит четыре «x» символа и $matches[2] четыре символа «z».
Потому что квантификатор «?» изменил поведение шаблона с «взять как можно БОЛЬШЕ» на «взять как можно МЕНЬШЕ».

Чтобы сделать нежадным весь шаблон, используем модификатор «U».

/*** string of characters ***/
$string = «xxxxzzzz» ;

/*** a non greedy match ***/
preg_match ( «/^(.*)(z+)$/U» , $string , $matches ) ;

/*** show the matches ***/
echo $matches [ 1 ] ;
echo «
» ;
echo $matches [ 2 ] ;
?>

Результат как в предыдущем примере.

Подводные камни c ? и U

Важно заметить, что модификатор «U» не только делает поиск нежадным, он инвертирует поведение жадности квантификатора «?».
Если использовался квантификатор «?» и одновременно модификатор «U», действие «?» будет инвертировано.

/*** string of characters ***/
$string = «xxxxzzzz» ;

/*** a non greedy match ***/
preg_match ( «/^(.*?)(z+)$/U» , $string , $matches ) ;

/*** show the matches ***/
echo $matches [ 1 ] ;
echo «
» ;
echo $matches [ 2 ] ;
?>

Результат скрипта:
xxxxzzz
Delimiters

В этом мане было рассмотрено много регулярок и все они разделялись слэшем «/».
Иногда нам нужно находить в шаблоне слэш и когда он одновременно является разделителем регуляного выражения,
нам придется экранировать каждый встречающийся слэш, что неудобно.

Поэтому в качестве разделителя можно взять любой символ, например #, @, ^ и т.п.

/*** get the host name from a url ***/
preg_match ( ‘#^(?:http://)?([^/]+)#i’ , «http://www.phpro.org/tutorials» , $matches ) ;

/*** show the host name ***/
echo $matches [ 1 ] ;
?>

Примеры

// the string to match against
$string = ‘The cat sat on the mat’ ;

// match the beginning of the string
echo preg_match ( «/^The/» , $string ) ;

// match the end of the string
// returns 1
echo preg_match ( «/mat \z /» , $string ) ;

// match anywhere in the string
// returns 0 as no match was found for dog.
echo preg_match ( «/dog/» , $string ) ;
?>

Поиск нескольких шаблонов

// the string to match against
$string = ‘The cat sat on the matthew’ ;

// matches the letter «a» followed by zero or more «t» characters
echo preg_match ( «/at*/» , $string ) ;

// matches the letter «a» followed by a «t» character that may or may not be present
echo preg_match ( «/at?/» , $string ) ;

// matches the letter «a» followed by one or more «t» characters
echo preg_match ( «/at+/» , $string ) ;

// matches a possible letter «e» followed by one of more «w» characters anchored to the end of the string
echo preg_match ( «/e?w+ \z /» , $string ) ;

// matches the letter «a» followed by exactly two «t» characters
echo preg_match ( «/at<2>/» , $string ) ;

// matches a possible letter «e» followed by exactly two «t» characters
echo preg_match ( «/e?t<2>/» , $string ) ;

// matches a possible letter «a» followed by exactly 2 to 6 «t» chars (att attt atttttt)
echo preg_match ( «/at<2,6>/» , $string ) ;

Запомните, preg_match() возвращает только 0 или 1, и останавливается после первого успешного нахождения шаблона.

Чтобы найти все совпадения — используйте preg_match_all().

Чит Шит

\w — Any “word” character (a-z 0-9 _)
\W — Any non “word” character
\s — Whitespace (space, tab CRLF)
\S — Any non whitepsace character
\d — Digits (0-9)
\D — Any non digit character
. — (Period) – Any character except newline

^ — Start of subject (or line in multiline mode)
$ — End of subject (or line in multiline mode)
[ — Start character class definition
] — End character class definition
| — Alternates, eg (a|b) matches a or b
( — Start subpattern
) — End subpattern
\ — Escape character

n- Zero or more of n
n+ — One or more of n
n? — Zero or one occurrences of n
— n occurrences exactly
— At least n occurrences
— Between n and m occurrences (inclusive)

i — Case Insensitive
m — Multiline mode — ^ and $ match start and end of lines
s — Dotall — . class includes newline
x — Extended– comments and whitespace
e — preg_replace only – enables evaluation of replacement as PHP code
S — Extra analysis of pattern
U — Pattern is ungreedy
u — Pattern is treated as UTF-8

\b — Word boundary
\B — Not a word boundary
\A — Start of subject
\Z — End of subject or newline at end
\z — End of subject
\G — First matching position in subject

(?=) — Positive look ahead assertion foo(?=bar) matches foo when followed by bar
(?!) — Negative look ahead assertion foo(?!bar) matches foo when not followed by bar
(? ) — Once-only subpatterns (?>\d+)bar Performance enhancing when bar not present
(?(x)) — Conditional subpatterns
(?(3)foo|fu)bar — Matches foo if 3rd subpattern has matched, fu if not
(?#) — Comment (?# Pattern does x y or z)

Дополнения от меня

Posix символьные классы

Дополнительные шорткуты для шаблонов. Могут применяться только внутри классов.
Пример для поиска числа с пробелами — preg_match(«@[[:space:]\d]+@», $string)

Внутренние модификаторы шаблонов

Модификаторы m, s, x, U, X, J могут использоваться внутри шаблона.
Например (?im) установит мультистроковой регистронезивисимый метод поиска для паттерна.
Отключить внутренние модификаторы можно перечислив их через дефис, например (?im-sx)

Пример:
шаблон (?i:foo) совпадет с «FoO»

Именованный «захват»

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

Записывается: (? ), (?’name’) или (?P ).
Раньше поддерживался только такой синтаксис: (?P ). [

preg_match ( ‘/Name: (.+), Age: ( \d +)/’ , $text , $matches ) ;
preg_match ( ‘/Name: (?P .+), Age: (?P \d +)/’ , $text , $matches ) ;
?>

Результат скрипта:
array(‘Name’ => ‘строка’, ‘Age’ => ‘число’)

Замена через callback-функцию

В php есть возможность указать функцию обратного вызова
для совпадений, если нам нужно проделать с ними необычные вещи.
Для этого используется preg_replace_callback.

\s * \w |’ ,
create_function (
‘$matches’ ,
‘return strtoupper($matches[0]);’
) ,
$line
) ;
?>

Данный код заменит все первые буквы в параграфах на заглавные.

В php >= 5.3 callback-функцию можно записать в сокращенном виде

\s * \w |’ ,
function ( $matches ) <
return strtoupper ( $matches [ 0 ] ) ;
> ,
$line
) ;
?>

Илон Маск рекомендует:  Где купить ссылки - вечные, качественные и эффективные!
Понравилась статья? Поделиться с друзьями:
Кодинг, CSS и SQL