Regular expression language — quick reference
Содержание:
- Соответствие определенному набору символов
- Опережающая проверка
- Замена: str.replace
- What Regular Expressions Are Exactly — Terminology
- Алгоритм[править]
- Максимализм квантификатора *
- Практические примеры сложных регулярных выражений
- Полезные методы работы с регулярными выражениями в JavaScript
- Тестирование
- Метасимволы
- Статичные регэкспы
- Строковые методы, поиск и замена
Соответствие определенному набору символов
Следующие спецсимволы используются для определения соответствия определенному набору символов.
\w – Соответствует буквенному или цифровому символу, а также знаку подчёркивания
\W – Соответствует любому символу, за исключением буквенного, цифрового и знака подчеркивания.
\d – Соответствует цифровому символу. Любые цифры от 0 до 9
\D – Соответствует не цифровому символу. Любые символы за исключением цифр от 0 до 9
\s – Соответствует пробельным символам. К ним относятся: пробел, табуляция и перевод строки
\S – Все символы за исключением пробельных
. – Соответствует любому символу за исключением перевода строки
– Обозначает диапазон символов. Например, выражение – соответствует символам “A”, “B”, “C”, “D” и “E”
– Соответствует перечисленным в символам в выражении. Например, – сработает только с символами “A”, “M” и “T”.
– Соответствует символам, не представленным в выражении. Например, с помощью найдутся все символы за исключением, “A”, “B”, “C”, “D” и “E”.
Опережающая проверка
Синтаксис опережающей проверки: .
Он означает: найди при условии, что за ним следует . Вместо и здесь может быть любой шаблон.
Для целого числа, за которым идёт знак , шаблон регулярного выражения будет :
Обратим внимание, что проверка – это именно проверка, содержимое скобок не включается в результат. При поиске движок регулярных выражений, найдя , проверяет есть ли после него
Если это не так, то игнорирует совпадение и продолжает поиск дальше
При поиске движок регулярных выражений, найдя , проверяет есть ли после него . Если это не так, то игнорирует совпадение и продолжает поиск дальше.
Возможны и более сложные проверки, например означает:
- Найти .
- Проверить, идёт ли сразу после (если нет – не подходит).
- Проверить, идёт ли сразу после (если нет – не подходит).
- Если обе проверки прошли – совпадение найдено.
То есть, этот шаблон означает, что мы ищем при условии, что за ним идёт и и .
Такое возможно только при условии, что шаблоны и не являются взаимно исключающими.
Например, ищет при условии, что за ним идёт пробел, и где-то впереди есть :
В нашей строке это как раз число .
Замена: str.replace
Метод заменяет совпадения с в строке на (все, если есть флаг , иначе только первое).
Например:
В строке замены мы можем использовать специальные комбинации символов для вставки фрагментов совпадения:
Спецсимволы | Действие в строке замены |
---|---|
вставляет всё найденное совпадение | |
вставляет часть строки до совпадения | |
вставляет часть строки после совпадения | |
если это 1-2 значное число, вставляет содержимое n-й скобочной группы регулярного выражения, больше об этом в главе Скобочные группы | |
вставляет содержимое скобочной группы с именем , также изучим в главе Скобочные группы | |
вставляет символ |
Пример с :
What Regular Expressions Are Exactly — Terminology
Basically, a regular expression is a pattern describing a certain amount of text. Their name comes from the mathematical theory on which they are based. But we will not dig into that. You will usually find the name abbreviated to «regex» or «regexp». This tutorial uses «regex», because it is easy to pronounce the plural «regexes». On this website, regular expressions are highlighted in red as regex.
This first example is actually a perfectly valid regex. It is the most basic pattern, simply matching the literal text regex. A “match” is the piece of text, or sequence of bytes or characters that pattern was found to correspond to by the regex processing software. Matches are highlighted in blue on this site.
Алгоритм[править]
Данный алгоритм работает быстрее недетерминированного конечного автомата, построенного по теореме Клини, но только для регулярных выражений, состоящих из символов:
- — один любой буквенный символ,
- — один любой символ,
- — символ начала текста,
- — символ конца текста,
- — предыдущий символ встречается ноль или более раз.
Например, для , очевидно, проще написать простой сопоставитель, чем строить НКА.
Псевдокодправить
function match(regexp: String, text: String): boolean if regexp == '^' return matchHere(regexp, text) int i = 0 while i text.length if matchHere(regexp, text) return true i++ return false
Функция проверяет есть ли вхождение регулярного выражения в любом месте в пределах текста. Если существует более одного вхождения, то найдется самое левое и самое короткое.
Логика функции проста. Если — первый символ регулярного выражения, то любое возможное вхождение должно начинаться в начале текста. То есть если — регулярное выражение, то должно входить в текст только с первой позиции текста, а не где-то в середине текста. Это проверяется путем сопоставления остатка регулярного выражения с текстом, начиная с первой позиции и нигде более.
В противном случае регулярное выражение может входить в текст в любой позиции. Это проверяется путем сопоставления регулярного выражения во всех позициях текста. Если регулярное выражение входит более одного раза в текст, то только самое левое вхождение будет распознано. То есть если — регулярное выражение, то для него найдется самое левое вхождение в текст.
function matchHere(regexp: String, text: String): boolean if regexp == '\0' return true if regexp == '*' return matchStar(regexp, regexp, text) if regexp == '$' and regexp == '\0' return text == '\0' if text != '\0' and (regexp == '.' or regexp == text) return matchHere(regexp, text) return false
Основная часть работы сделана в , которая сопоставляет регулярное выражение с текстом в текущей позиции. Функция пытается сопоставить первый символ регулярного выражения с первым символом текста. В случае успеха мы можем сравнить следующий символ регулярного выражения со следующим символом текста, вызвав рекурсивно. Иначе нет совпадения с регулярным выражением в текущей позиции текста.
function matchStar(c: char, regexp: String, text: String): boolean int i = 0 while i text.length and (text == c or c == '.') if matchHere(regexp, text) return true i++ return false
Рассмотрим возможные случаи:
- Если в ходе рекурсии регулярное выражение осталось пустым то текст допускается этим регулярным выражением.
- Если регулярное выражение имеет вид , то вызывается функция которая пытается сопоставить повторение символа , начиная с нуля повторений и увеличивая их количество, пока не найдет совпадение с оставшимся текстом. Если совпадение не будет найдено, то регулярное выражение не допускает текст. Текущая реализация ищет «кратчайшее совпадение», которое хорошо подходит для сопоставления с образцом, как в grep, где нужно как можно быстрее найти совпадение. «Наидлиннейшее совпадение» более интуитивно и больше подходит для текстовых редакторов, где найденное заменят на что-то. Большинство современных библиотек для работы с регулярными выражениями предоставляют оба варианта.
- Если регулярное выражение это , то оно допускает этот текст тогда и только тогда, когда текст закончился.
- Если первый символ текста совпал с первым символом регулярного выражения, то нужно проверить совпадают ли следующий символ регулярного выражения со следующим символом текста, сделав рекурсивный вызов .
- Если все предыдущие попытки найти совпадения провалились, то никакая подстрока из текста не допускается регулярным выражением.
Модификацииправить
Немного изменим функцию для поиск самого левого и самого длинного вхождения :
- Найдем максимальную последовательность подряд идущих символов . Назовем ее .
- Сопоставим часть текста без с остатком регулярного выражения.
- Если части совпали, то текст допускается этим регулярным выражением. Иначе, если пусто, то текст не допускается этим регулярным выражением, иначе убираем один символ из и повторяем шаг .
Псевдокодправить
function matchStar(c: char, regexp: String, text: String): boolean int i for (i = 0; text != '\0' and (text == c or c == '.'); i++) while i 0 if matchHere(regexp, text) return true i-- return false
Максимализм квантификатора *
Регулярное выражение .* всегда распространяет совпадение до конца строки. Это связано с тем, что .* стремится захватить все, что может. Впрочем, позднее часть захваченного может быть возвращена, если это необходимо для общего совпадения. Иногда это поведение вызывает немало проблем. Рассмотрим регулярное выражение для поиска текста, заключенного в кавычки. На первый взгляд напрашивается простое ».*», но попробуйте на основании того, что нам известно о .*, предположить, какое совпадение будет найдено в строке:
The name «McDonald’s» is said «makudonarudo» in Japanese
После совпадения первого символа » управление передается конструкции .*, которая немедленно захватывает все символы до конца строки. Она начинает нехотя отступать (под нажимом механизма регулярных выражений), но только до тех пор, пока не будет найдено совпадение для последней кавычки. Если прокрутить происходящее в голове, вы поймете, что найденное совпадение будет выглядеть так(выделено нижним подчеркиванием):
The name «McDonald’s» is said «makudonarudo» in Japanese
Найден совсем не тот текст, который мы искали. Это одна из причин, по которым не стоит злоупотреблять .*, – если не учитывать проблем максимального совпадения, эта конструкция часто приводит к неожиданным результатам.
Как же ограничить совпадение строкой «McDonald’s»? Главное – понять, что между кавычками должно находиться не «все, что угодно», а «все, что угодно, кроме кавычек». Если вместо .* воспользоваться выражением *, совпадение не пройдет дальше закрывающей кавычки.
При поиске совпадения для »*» механизм ведет себя практически так же. После совпадения первой кавычки * стремится захватить как можно большее потенциальное совпадение. В данном случае это совпадение распространяется до кавычки, следующей после McDonald’s. На этом месте поиск прекращается, поскольку не совпадает с кавычкой, после чего управление передается закрывающей кавычке в регулярном выражении. Она благополучно совпадает, обеспечивая общее совпадение:
The name «McDonald’s» is said «makudonarudo» in Japanese
На самом деле в этом примере возможен неожиданный поворот, связанный с тем, что в большинстве диалектов может совпадать с символом новой строки, a . – не может. Если вы хотите предотвратить возможный выход за границу логической строки, используйте выражение .
Практические примеры сложных регулярных выражений
Теперь, когда вы знаете теорию и основной синтаксис регулярных выражений в PHP, пришло время создать и проанализировать некоторые более сложные примеры.
1) Проверка имени пользователя с помощью регулярного выражения
Начнем с проверки имени пользователя. Если у вас есть форма регистрации, вам понадобится проверять на правильность имена пользователей. Предположим, вы не хотите, чтобы в имени были какие-либо специальные символы, кроме «» и, конечно, имя должно содержать буквы и возможно цифры. Кроме того, вам может понадобиться контролировать длину имени пользователя, например от 4 до 20 символов.
Сначала нам нужно определить доступные символы. Это можно реализовать с помощью следующего кода:
После этого нам нужно ограничить количество символов следующим кодом:
{4,20}
Теперь собираем это регулярное выражение вместе:
^{4,20}$
В случае Perl-совместимого регулярного выражения заключите его символами ‘‘. Итоговый PHP-код выглядит так:
<?php $pattern = '/^{4,20}$/'; $username = "demo_user-123"; if (preg_match($pattern, $username)) { echo "Проверка пройдена успешно!"; } else { echo "Проверка не пройдена!"; } ?>
2) Проверка шестнадцатеричного кода цвета регулярным выражением
Шестнадцатеричный код цвета выглядит так: , также допустимо использование краткой формы, например . В обоих случаях код цвета начинается с и затем идут ровно 3 или 6 цифр или букв от a до f.
Итак, проверяем начало кода:
^#
Затем проверяем диапазон допустимых символов:
После этого проверяем допустимую длину кода (она может быть либо 3, либо 6). Полный код регулярного выражения выйдет следующим:
^#(({3}$)|({6}$))
Здесь мы используем логический оператор, чтобы сначала проверить код вида , а затем код вида . Итоговый PHP-код проверки регулярным выражением выглядит так:
<?php $pattern = '/^#(({3}$)|({6}$))/'; $color = "#1AA"; if (preg_match($pattern, $color)) { echo "Проверка пройдена успешно!"; } else { echo "Проверка не пройдена!"; } ?>
3) Проверка электронной почты клиента с использованием регулярного выражения
Теперь давайте посмотрим, как мы можем проверить адрес электронной почты с помощью регулярных выражений. Сначала внимательно рассмотрите следующие примеры адресов почты:
john.doe@test.com john@demo.ua john_123.doe@test.info
Как мы можем видеть, символ является обязательным элементом в адресе электронной почты. Помимо этого должен быть какой-то набор символов до и после этого элемента. Точнее, после него должно идти допустимое доменное имя.
Таким образом, первая часть должна быть строкой с буквами, цифрами или некоторыми специальными символами, такими как . В шаблоне мы можем написать это следующим образом:
^+
Доменное имя всегда имеет, скажем, имя и tld (top-level domain) – т.е, доменную зону. Доменная зона – это , , и тому подобное. Это означает, что шаблон регулярного выражения для домена будет выглядеть так:
+\.{2,5}$
Теперь, если мы соберем все в кучу, то получим полный шаблон регулярного выражения для проверки адреса электронной почты:
^+@+\.{2,5}$
В коде PHP эта проверка будет выглядеть следующим образом:
<?php $pattern = '/^+@+\.{2,5}$/'; $email = "john_123.doe@test.info"; if (preg_match($pattern, $email)) { echo "Проверка пройдена успешно!"; } else { echo "Проверка не пройдена!"; } ?>
Надеемся, что сегодняшняя статья помогла вам при знакомстве с регулярными выражениями в PHP, а практические примеры пригодятся вам при использовании регулярных выражений в собственных PHP скриптах.
-
3059
-
35
-
Опубликовано 16/04/2019
-
PHP, Уроки программирования
Полезные методы работы с регулярными выражениями в JavaScript
Регулярные выражения, создаваемые с использованием флагов и последовательностей символов, которые мы обсуждали ранее в этой статье, предназначены для использования с различными методами JavaScript для поиска, замены или разделения строк.
Вот некоторые методы, связанные с регулярными выражениями.
► test() – проверяет, содержит ли основная строка подстроку, которая соответствует шаблону, заданному данным регулярным выражением. При успешном совпадении метод возвращает true, в противном случае — false.
JavaScript
var textA = 'I like APPles very much'; var textB = 'I like APPles'; var regexOne = /apples$/i // вернет false console.log(regexOne.test(textA)); // вернет true console.log(regexOne.test(textB));
В приведённом выше примере приведено регулярное выражение, предназначенное для поиска слова “apples” в случае, если оно расположено в конце строки. Поэтому в первом случае метод вернет false.
► search() – проверяет, содержит ли основная строка подстроку, которая соответствует шаблону, заданному данным регулярным выражением. Метод возвращает индекс совпадения при успехе и -1 в противном случае.
JavaScript
var textA = 'I like APPles very much'; var regexOne = /apples/; var regexTwo = /apples/i; // Результат: -1 console.log(textA.search(regexOne)); // Результат: 7 console.log(textA.search(regexTwo));
В данном примере проверка по превому регулярному выражению вернет -1, потому что не указан флаг нечувствительности к регистру.
► match() – осуществляет поиск подстроки в основной строке. Подстрока должна соответствовать шаблону, заданному данным регулярным выражением. Если используется флаг g, то несколько совпадений будут возвращены в виде массива.
JavaScript
var textA = 'All I see here are apples, APPles and apPleS'; var regexOne = /apples/gi; // Результат: console.log(textA.match(regexOne));
► exec() – производит поиск подстроки в основной строке. В случае, если подстрока соответствует шаблону, заданному данным регулярным выражением, возвращает массив с результатами или null. В свойстве input хранится оригинальная строка
JavaScript
var textA = 'Do you like apples?'; var regexOne = /apples/; // Результат: apples console.log(regexOne.exec(textA)); // Результат : Do you like apples? console.log(regexOne.exec(textA).input);
► replace() – ищет подстроку, соответствующую заданному шаблону и заменяет ее на предоставленную заменяющую строку.
JavaScript
var textA = 'Do you like aPPles?'; var regexOne = /apples/i // Результат: Do you like mangoes? console.log(textA.replace(regexOne, 'mangoes'));
► split() – Этот метод позволит вам разбить основную строку на подстроки на основе разделителя, представленного в виде регулярного выражения.
JavaScript
var textA = 'This 593 string will be brok294en at places where d1gits are.'; var regexOne = /\d+/g // Результат : console.log(textA.split(regexOne))
Тестирование
Вы можете использовать тестовые данные для проверки работоспособности ваших регулярных выражений. Ваше регулярное выражение может корректно работать с одним набором тестовых данных и не очень корректно с другим набором. Как и везде, с практикой вы научитесь создавать объемные тестовые данные для полной проверки ваших выражений.
В качестве примера следующее регулярное выражение ищет , за которым следует любой символ. Если бы наша задача состояла в том, чтобы найти , за которым следует или (как в примере, приведенном выше), то мы бы могли использовать следующие тестовые данные и прийти к неверному заключению, что наше регулярное выражение полностью рабочее:
Дело в том, что мы указали данные, в которых наше выражение на все 100% сработает, но это не те данные, которые соответствуют заданию в полной мере.
Когда вы используете тестовые данные, убедитесь, что вы включили все, даже крайние случаи.
Повторюсь, это служит лишь примером и маловероятно, что может оказаться полезным на данном этапе. Но как только мы начнем погружаться в изучение регулярных выражений, то всё станет на свои места.
Метасимволы
Символ | Описание |
---|---|
. | Позволяет найти один символ, кроме символа новой строки, или символа конца строки (\n, \r, \u2028 или \u2029). |
\d | Позволяет найти символ цифры в базовом латинском алфавите. Эквивалентин использованию набору символов . |
\D | Позволяет найти любой символ, который не является цифрой в базовом латинском алфавите. Эквивалентен набору символов . |
\s | Позволяет найти одиночный пробельный символ. Под пробельным символом понимается пробел, табуляция, перевод страницы, перевод строки и другие пробельные символы Юникода. Эквивалентен набору символов . |
\S | Позволяет найти одиночный символ, который не является пробельным. Под пробельным символом понимается пробел, табуляция, перевод страницы, перевод строки и другие пробельные символы Юникода. Эквивалентен набору символов . |
Позволяет найти символ backspace (специальный символ \b, U+0008). | |
\0 | Позволяет найти символ 0 (ноль). |
\n | Позволяет найти символ новой строки. |
\f | Позволяет найти символ перевода страницы. |
\r | Позволяет найти символ возврата каретки. |
\t | Позволяет найти символ горизонтальной табуляции. |
\v | Позволяет найти символ вертикальной табуляции. |
\w | Позволяет найти любой буквенно-цифровой символ базового латинского алфавита, включая подчеркивание. Эквивалентен набору символов . |
\W | Позволяет найти любой символ, который не является символом из базового латинского алфавита. Эквивалентен набору символов . |
\cX | Позволяет найти контрольный символ в строке. Где X — буква от A до Z. Например, /\cM/ обозначает символ Ctrl-M. |
\xhh | Позволяет найти символ, используя шестнадцатеричное значение (hh — двухзначное шестнадцатеричное значение). |
\uhhhh | Позволяет найти символ, используя кодировку UTF-16 (hhhh — четырехзначное шестнадцатеричное значение). |
\u{hhhh} или \u{hhhhh} | Позволяет найти символ со значением Юникода U+hhhh или U+hhhhh (шестнадцатеричное значение). Только когда задан флаг u. |
\ | Указывает, что следующий символ является специальным и не должен интерпретироваться буквально. Для символов, которые обычно трактуются специальным образом, указывает, что следующий символ не является специальным и должен интерпретироваться буквально. |
Статичные регэкспы
В некоторых реализациях javascript регэкспы, заданные коротким синтаксисом /…/ — статичны. То есть, такой объект создается один раз в некоторых реализациях JS, например в Firefox. В Chrome все ок.
function f() { // при многократных заходах в функцию объект один и тот же var re = /lalala/ }
По стандарту эта возможность разрешена ES3, но запрещена ES5.
Из-за того, что при глобальном поиске меняется, а сам объект регэкспа статичен, первый поиск увеличивает , а последующие — продолжают искать со старого , т.е. могут возвращать не все результаты.
При поиске всех совпадений в цикле проблем не возникает, т.к. последняя итерация (неудачная) обнуляет .
Строковые методы, поиск и замена
Следующие методы работают с регулярными выражениями из строк.
Все методы, кроме replace, можно вызывать как с объектами типа regexp в аргументах, так и со строками, которые автоматом преобразуются в объекты RegExp.
Так что вызовы эквивалентны:
var i = str.search(/\s/) var i = str.search("\\s")
При использовании кавычек нужно дублировать \ и нет возможности указать флаги. Если регулярное выражение уже задано строкой, то бывает удобна и полная форма
var regText = "\\s" var i = str.search(new RegExp(regText, "g"))
Возвращает индекс регулярного выражения в строке, или -1.
Если Вы хотите знать, подходит ли строка под регулярное выражение, используйте метод (аналогично RegExp-методы ). Чтобы получить больше информации, используйте более медленный метод (аналогичный методу ).
Этот пример выводит сообщение, в зависимости от того, подходит ли строка под регулярное выражение.
function testinput(re, str){ if (str.search(re) != -1) midstring = " contains "; else midstring = " does not contain "; document.write (str + midstring + re.source); }
Если в regexp нет флага , то возвращает тот же результат, что .
Если в regexp есть флаг , то возвращает массив со всеми совпадениями.
Чтобы просто узнать, подходит ли строка под регулярное выражение , используйте .
Если Вы хотите получить первый результат — попробуйте r.
В следующем примере используется, чтобы найти «Chapter», за которой следует 1 или более цифр, а затем цифры, разделенные точкой. В регулярном выражении есть флаг , так что регистр будет игнорироваться.
str = "For more information, see Chapter 3.4.5.1"; re = /chapter (\d+(\.\d)*)/i; found = str.match(re); alert(found);
Скрипт выдаст массив из совпадений:
- Chapter 3.4.5.1 — полностью совпавшая строка
- 3.4.5.1 — первая скобка
- .1 — внутренняя скобка
Следующий пример демонстрирует использование флагов глобального и регистронезависимого поиска с . Будут найдены все буквы от А до Е и от а до е, каждая — в отдельном элементе массива.
var str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; var regexp = //gi; var matches = str.match(regexp); document.write(matches); // matches =
Метод replace может заменять вхождения регулярного выражения не только на строку, но и на результат выполнения функции. Его полный синтаксис — такой:
var newString = str.replace(regexp/substr, newSubStr/function)
- Объект RegExp. Его вхождения будут заменены на значение, которое вернет параметр номер 2
- Строка, которая будет заменена на .
- Строка, которая заменяет подстроку из аргумента номер 1.
- Функция, которая может быть вызвана для генерации новой подстроки (чтобы подставить ее вместо подстроки, полученной из аргумента 1).
Метод не меняет строку, на которой вызван, а просто возвращает новую, измененную строку.
Чтобы осуществить глобальную замену, включите в регулярное выражение флаг .
Если первый аргумент — строка, то она не преобразуется в регулярное выражение, так что, например,
var ab = "a b".replace("\\s","..") // = "a b"
Вызов replace оставил строку без изменения, т.к искал не регулярное выражение , а строку «\s».
В строке замены могут быть такие спецсимволы:
Pattern | Inserts |
Вставляет «$». | |
Вставляет найденную подстроку. | |
Вставляет часть строки, которая предшествует найденному вхождению. | |
Вставляет часть строки, которая идет после найденного вхождения. | |
or | Где или — десятичные цифры, вставляет подстроку вхождения, запомненную -й вложенной скобкой, если первый аргумент — объект RegExp. |
Если Вы указываете вторым параметром функцию, то она выполняется при каждом совпадении.
В функции можно динамически генерировать и возвращать строку подстановки.
Первый параметр функции — найденная подстрока. Если первым аргументом является объект , то следующие параметров содержат совпадения из вложенных скобок. Последние два параметра — позиция в строке, на которой произошло совпадение и сама строка.
Например, следующий вызов возвратит XXzzzz — XX , zzzz.
function replacer(str, p1, p2, offset, s) { return str + " - " + p1 + " , " + p2; } var newString = "XXzzzz".replace(/(X*)(z*)/, replacer)
Как видите, тут две скобки в регулярном выражении, и потому в функции два параметра , .
Если бы были три скобки, то в функцию пришлось бы добавить параметр .
Следующая функция заменяет слова типа на :
function styleHyphenFormat(propertyName) { function upperToHyphenLower(match) { return '-' + match.toLowerCase(); } return propertyName.replace(//, upperToHyphenLower); }