Регулярное выражение — это описание шаблона символов. Самый простой шаблон, который мы можем описать — это строка (или последовательность) символов. Например, я хочу выполнить поиск символов th
(или, если говорить более конкретно, я ищу символ t
, за которым непосредственно следует символ h
) в следующем наборе символов:
Регулярное выражение: th
Пример: There is no theory of evolution. Only a list of animals Chuck Norris allows to live.
Вы можете быть удивлены, почему не было найдено совпадение в слове There
. Дело в том, что это слово содержит заглавную букву T
, а не строчную, как в искомом регулярном выражении. Мы знаем, что это один и тот же символ, просто в другой форме. Однако это не относится к регулярным выражениям. Регулярные выражения не определяют значения искомой последовательности. Всё, что они делают — это ищут точные совпадения с тем, что описывает шаблон.
Очень простое регулярное выражение, подобное рассмотренному выше th
, на самом деле ничем не отличается от поискового запроса, который вы можете выполнить в поисковой системе (Google/Яндекс) или в вашем любимом текстовом редакторе.
Метасимволы
Символ точки (.
) является метасимволом. Метасимволы — это символы, которые имеют особое значение. Они помогают создавать более интересные шаблоны, чем просто набор конкретных символов. Практически всё, что мы будем рассматривать — будет метасимволами.
Точка (.
) представляет собой любой символ. В следующем примере мы ищем символ b
, за которым следует любой символ, а за ним символ g
:
Регулярное выражение: b.g
Пример: The big bag of bits was bugged.
Важно отметить, что точка (.
) соответствует только одному символу. Мы можем заставить её соответствовать более чем одному символу, используя множители, которые мы рассмотрим ниже. Кроме того, вы также можете искать несколько символов с помощью точки следующим образом:
Регулярное выражение: l..e
Пример: You can live like a king but make sure it isn't a lie.
В примере, приведенном выше, мы ищем букву l
, за которой следуют любые два символа, и за которыми следует e
.
Диапазоны символов
Символ точки (.
) позволяет нам установить соответствие любому символу. Но иногда нам необходимо быть более конкретными. В этом случае будут полезны диапазоны. Мы указываем диапазон символов, заключая их в квадратные скобки []
:
Регулярное выражение: t[eo]d
Пример: When today is over Ted will have a tedious time tidying up.
В регулярном выражении, приведенном выше, мы ищем символ t
, за которым следует либо символ e
, либо o
, и за которым следует символ d
.
Количество символов, которые вы можете поместить в квадратные скобки, не ограничено. Вы можете разместить один символ, например, [у]
(это было бы немного глупо, но, тем не менее, это не нарушает правила) или вы можете указать несколько символов, например, [Grf4s2 # lknx]
.
Короткая запись
Допустим, мы хотим найти наличие цифр от 1 до 8. Мы могли бы использовать для поиска следующий диапазон: [12345678]
, но есть вариант получше:
Регулярное выражение: [1-8]
Пример: Room Allocations: G4 G9 F2 H1 L0 K7 M9
Вы можете комбинировать набор символов вместе с другими символами:
Регулярное выражение: [1-49]
Пример: Room Allocations: G4 G9 F2 H1 L0 K7 M9
В регулярном выражении, приведенном выше, мы ищем цифры 1, 2, 3, 4 или 9.
Мы также можем объединить несколько наборов. В следующем регулярном выражении мы ищем 1, 2, 3, 4, 5, a, b, c, d, e, f, x:
Регулярное выражение: [1-5a-fx]
Пример: A random set of characters: y, w, a, r, f, 4, 9, 6, 3, p, x, t
Использование наборов символов иногда может привести к странному поведению. Например, вы можете использовать диапазон [a-f]
и обнаружить, что ему соответствует символ D
. Это связано с таблицами символов, которые использует система. В большинстве систем есть таблица символов, в которой сначала идут все строчные буквы, а затем все заглавные (например, abcdef...xyzABCD...
). Однако некоторые системы чередуют строчные и прописные буквы (например, aAbBcCdD...yYzZ
). Если вы столкнулись с каким-то странным поведением и при этом используете диапазоны, то это первое, что нужно проверить.
Поиск несоответствующих символов
Иногда нам может понадобиться найти символ, который не входит в диапазон искомых. Мы можем это сделать, поместив знак вставки (^
) в начало диапазона:
Регулярное выражение: t[^eo]d
Пример: When today is over Ted will have a tedious time tidying up.
Совет: Любые символы, которые обычно имеют особое значение (метасимволы), теряют свое особое значение и становятся обычными символами, находясь внутри диапазона. Исключением является знак вставки (^
), который приобретает новое значение — отрицание.
Мультипликаторы
Мультипликаторы позволяют увеличить количество раз появления элемента в нашем регулярном выражении. Вот основной набор мультипликаторов:
*
— значение встречается 0 или более раз;
+
— значение встречается 1 или более раз;
?
— значение встречается 0 или 1 раз;
{5}
— значение встречается 5 раз;
{3,7}
— значение встречается от 3 до 7 раз;
{2,}
— значение встречается не менее 2 раз.
Их действие распространяется на всё, что находится прямо перед ними. Это может быть обычный символ, например:
Регулярное выражение: lo*
Пример: Are you looking at the lock or the silk?
В примере, приведенном выше, мы ищем символ l
, за которым следует символ o
ноль или более раз. Вот почему l
в слове silk
также является совпадением (это l
, за которым идет символ o
ноль раз).
Или это может быть метасимвол, например:
Регулярное выражение: l.*k
Пример: Are you looking at the lock or the silk?
На первый взгляд такой результат может показаться вам немного странным. Регулярное выражение .*
соответствует повторению ноль или более раз любого символа. Вы могли бы подумать, что при нахождении первого k
, будет сказано «да, я нашел совпадение», но на самом деле говорится, что «k
является любым символом, поэтому давайте посмотрим, на сколько длинным может быть соответствие», и поиск продолжится, пока не будет найден последний k
в строке.
Это то, что называется «жадным сопоставлением». Это нормальное поведение — пытаться найти самую большую строку, которая может соответствовать шаблону. Мы можем изменить это поведение и сделать его «нежадным», поместив вопросительный знак (?
) после мультипликатора (что может показаться немного запутанным, поскольку вопросительный знак сам по себе является множителем):
Регулярное выражение: l.*?k
Пример: Are you looking at the lock or the silk?
Экранирование
Иногда нам может потребоваться найти один из символов, который является метасимволом. Для этого мы используем то, что называется экранированием. Поместив обратную косую черту (\
) перед метасимволом, мы можем удалить его особое значение. Допустим, что нам нужно найти появление слова this
, которое является последним словом в предложении.
Если бы мы сделали следующее:
Регулярное выражение: this.
Пример: Surely this regular expression should match this.
То нашли бы this.
как в конце предложения, так и в начале, потому что точка в регулярном выражении обычно соответствует любому символу.
Решением будет следующее:
Регулярное выражение: this\.
Пример: Surely this regular expression should match this.
Совет: Когда метасимволы являются частью вашей искомой строки, то очень легко забыть об их экранировании. Если в результатах ваших регулярных выражений что-то не так, то внимательно обследуйте метасимволы, которые вы, возможно, забыли экранировать.
Механизм работы регулярных выражений
Теперь, когда у вас есть представление о том, что такое регулярные выражения, мы можем рассмотреть то, что происходит «под капотом».
Итак, мы имеем указатель, который постепенно перемещается по строке поиска. Как только он сталкивается с символом, который соответствует началу регулярного выражения, он останавливается. Теперь запускается второй указатель, который перемещается вперед от первого указателя, символ за символом, проверяя с каждым шагом, сохраняется ли соответствие шаблону или нет. Если мы доберемся до конца шаблона и сохранится соответствие, то мы нашли совпадение. Если на любом шаге происходит сбой, то второй указатель отбрасывается, а основной указатель продолжает движение по строке.
Заключение
Резюмируем то, что мы узнали:
.
— соответствует любому символу;
[ ]
— совпадает с символом из диапазона, содержащемуся в квадратных скобках;
[^]
— соответствует символам, которые не входят в диапазон, содержащийся в квадратных скобках;
*
— совпадение 0 или более раз с указанным элементом;
+
— совпадение 1 или более раз с указанным элементом;
?
— совпадение 0 или 1 раз с указанным элементом;
{n}
— точное совпадение n
раз с указанным элементом;
{n, m}
— точное совпадение от n
до m
раз с указанным элементом;
{n, }
— точное совпадение n
или более раз с указанным элементом;
\
— экранирование или отмена специального значения указанного символа.