Если вы пишите прототип, или если скорость работы не принципиальна — используйте регулярные выражения. Это ускорит скорость разработки и уменьшит количество кода. Но, если итоговое решение будет работать медленно, то его всегда можно будет переписать без использования регулярных выражений.
- PCRE, применяется в PHP и др. ПО
- ECMA 262, применяется в JavaScript
- есть и другие достойные внимания, но в этом документе не рассматриваются
Тип обработки | JavaScript | PHP |
---|---|---|
Проверка соответствия (валидация) | RegExp.test() |
preg_match() , preg_grep() |
Поиск и захват подстрок | RegExp.exec() , String.match() , String.search() |
preg_match_all() |
Поиск, захват и замена подстрок | String.replace() |
preg_replace() , preg_replace_callback() , preg_replace_callback_array() , preg_filter() |
Поиск и разбиение на подстроки | String.split() |
preg_split() |
- Полное — вся строка соответствует шаблону регулярного выражения, которое всегда начинается с
^
и заканчивается на$
. - Частичное — часть строки соответствует шаблону регулярного выражения. Наличие символов
^
и$
опционально.
Полное соответствие обычно используют для валидации (проверки) строк на соответствие или не соответствие регулярному выражению. А частичное — для синтаксического анализа (парсинга) и лексического анализа (токенизации) строк.
Из частичного соответствия очень легко сделать полное, указав ^
в начале и $
в конце. В обратную сторону — сложнее, т.к. при необходимости необходимо явно указывать границы начала и конца искомой подстроки. Обычно это делают через (?<!…)
и (?!…)
соответственно.
Главная проблема медлительности — многочисленные откаты в случае неудачи в одной из веток поиска, которые могут привести к превышению максимального времени выполнения. Подробнее см. Catastrophic Backtracking.
- Пример долго выполняющегося регулярного выражения PCRE и его оптимизированной версии, работающей почти в 10 раз быстрее: PCRE
- Используйте атомарную группировку
(?>…)
и/или однократные квантификаторы:…?+
,…*+
,…++
. В диалекте JS нет такой встроенной возможности, но можно использовать конструкцию типа(?=(…))\1
, которая является аналогом. - Не используйте вложенные циклы типа
(…+)+
. Используйте конструкции типа(?!…)(…)+
,(?=…)(…)+
,(…)+(?<!…)
,(…)+(?<=…)
. - В случае отсутствия
^
задавайте явно границу начала совпадения через\b
или(?<!…)
. В случае отсутствия$
задавайте явно границу совпадения через\b
или(?!…)
. - Замените нежадные квантификаторы типа
.*?
на жадные. Но часть рег. выражения нужно будет немного переписать и усложнить для увеличения скорости. - Не используйте флаг
/u
(юникод в PCRE). Возможно, часть рег. выражения нужно будет немного переписать и усложнить для увеличения скорости.
- Регулярные выражения PCRE пока поддерживают просмотр назад только с фиксированной длиной. Т.е. внутри
(?<!…)
нельзя использовать квантификаторы?
,*
,+
,{…,…}
. Но есть способ обойти это ограничение, используя\K
. - Регулярные выражения JS пока не поддерживают всех возможностей PCRE, но есть готовые решения:
- Библиотека
XRegExp
, которая расширяет стандартные возможности рег. выражений в JS до уровня PCRE. String.prototype.matchRecursive()
— реализация JavaScript методаString.match()
с учётом рекурсии: JS Fiddle- Генератор регулярного выражения до заданной глубины рекурсии
(?R)
(TODO сделать форму ввода): JS Fiddle
- Библиотека
Используйте сервис regex101.com
для написания и тестирования ваших регурярных выражений, а так же для поиска и замены подстрок через регулярные выражения в диалектах PRCE, JS, Python, Golang.
Каждое регулярное выражение написано так, чтобы оно
- работало максимально быстро (по советам выше)
- было читабельным с выделением логических частей (используется флаг
/x
) и описанием в комментариях (#
)
- Целые:
/^[-−]? (?:[1-9]\d*|0) $/sx
- Целые и десятичные:
/^[-−]? (?:[1-9]\d*|0) (?:\.\d+)? $/sx
- Денежный формат:
/^[-−]? (?:[1-9]\d*|0) (?:\.\d{1,2})? $/sx
- Число с разделением тысячных через запятую и десятичными: PCRE
- Дата в формате
ГГГГ-ММ-ДД
:/^\d{4}-\d{2}-\d{2}$/sSX
- Время в формате
ЧЧ:ММ:СС
:/^\d{2}:\d{2}(:\d{2})?$/sSX
- Валидация даты в формате
ГГГГ-ММ-ДД
с проверкой корректности года, месяца и дня, но без проверки YYYY-02-29 в високосных годах (нужно доделать): PCRE
- Валидация IPv4 + IPv6: PCRE, link. В языках программирования есть готовый валидатор: PHP —
filter_var()
, NodeJS —net.isIP()
. - Захват адреса электронной почты (Email address) из текста: PCRE
- Захват многострочных комментариев, где они НЕ могут быть вложены друг в друга (C-style), в 3 раза эффективнее, чем
/\* .*? \*/
: PCRE - Захват многострочных комментариев, где они могут быть вложены друг в друга (PostgreSql): PCRE
- Base64: PCRE
Включая номера, которые пытаются скрыть, используя разные разделители цифр.
PCRE
/
(?<!\d) #boundary
( #1 код страны для РФ
\+7 [^\d\n,;]{0,5}
| [78] [^\d\n,;]{0,5}
)?
(?<!\+)
([489][\dOО]{2}) #2 код города или код мобильного оператора для РФ (цифра, поддельная русская/англ. буква, похожая на ноль)
( (?:(?!\x20*[дД][оО]\x20*\d) #не является диапазоном
(?!\x20*р(?:уб)?[^а-я]) #не является денежной суммой
[^\d\n,;]{0,5}
[\dOО]
){7}
) #3 номер телефона для РФ 7 цифр
(?!@[a-zA-Zа-яёА-ЯЁ\d]+\.) #не является частью email
(?!\x20*(?:руб|р\.|года)) #не является частью денежной суммы или указанием года
(?!\d) #boundary
/gxs
Тестирование
# Invalid
79261234567@mail.ru
79261234567@почта.москва
+7926123456
+7 926123456
+7 926 123456
+7(926)123456
+9261234567
# Valid
## РФ fake
9261234567
79261234567
8 916 123 тире 45 тире 67
8_916_123_45_67
## РФ regular
++79261234567
+79261234567
+7 9261234567
+7 926 1234567
+7 968 123-45-67
+7(965)123-45-67 (доб. 318)
+7 965 123 45 67 #221
+7 965 123 45 67+221
+7 (495) 361-999-1
+7 (83166) 1-23-45
+7 831 66 1-23-45
## РФ local:
89261234567
8(965)1234567 c 10 до 24
8(965)123 45 67 (с 11.00 до 20.00)
8 965 66-38-5-85 (с 12:00 до 18:00)
8-965-663-85-85 (from 10am to 18pm)
8 (495) 361-999-1 (from 8 AM to 9 PM)
8 8316 123 4 56
## UAE:
+971 2 4567890
+971 (0)2 4567890
+971 4 123 45 67
+971-4-1234567
+971-50-1234567
+971-50-123-45-67
## Germany:
+49 511 4735138
+49 511 473-51-38
+49(511)473-51-38
+49 (511) 473-51-38
## Argentina
+54 9 2982 123456
## Moldova
+373 68 007777
+373 68 007777
- Захват xml и html сущностей: PCRE, JS (strict); PCRE (non strict). См. так же список именованных сущностей в JSON.
- Захват заданных html тегов с учётом их парности без вложенных таких же тегов: PCRE, JS
- Захват заданных html тегов с учётом их парности и вложенности друг в друга (рекурсивно): PCRE, JS
- Вставляет теги
</li>
там, где они пропущены (чинит некорректную вложенность тегов<li>
): PCRE
- Удаление начальных и конечных пробелов: PCRE
- Валидация слова на английском языке во множественном числе: PCRE
- Валидация ФИО на русском или английском языке: PCRE
- Выделение слов и чисел из текста PCRE
- Поиск дубликатов в списке через запятую PCRE
- Детектирование SQL на модификацию данных: PCRE
- Разбиение SQL на несколько запросов по символу
;
: PCRE
Захват квотированной строки (PCRE):
(?>
'(?>[^']+|'')*' #string constants
| \b[Ee]'(?>[^\\']+|''|\\.)*' #string constants with C-style escapes
| (?<stringDollarTag>\$[a-zA-Z\d_]*\$) #dollar-quoted string
[^$]*+ #speed improves
.*?
\k<stringDollarTag>
)
Захват квотированного названия объекта БД (PCRE):
"(?>[^"]+|"")*"
Захват комментариев (PCRE):
(?>
#singe-line comment
(?<singeLineComment>-- [^\r\n]*+)
|
#multi-line comment
(?<MutilineComment>
/\*
[^*/]*+
(?> [^*/]++
| \*[^/]
| /[^*]
| (?&MutilineComment) #recursive
)*+
\*/
)
)
Захват квотированной строки (PCRE):
(?>"(?>[^\\"]+|""|\\.)*"|'(?>[^\\']+|''|\\.)*')
Захват квотированного названия объекта БД (PCRE):
`(?>[^\\`]+|``|\\.)*`
Захват комментариев (PCRE):
(?>
#singe-line comment
(?<singeLineComment>-- (?=\s) [^\r\n]*+)
|
#multi-line comment by Jeffrey Friedl (fastest)
(?<multiLineComment>
/\*
[^*]* \*+
(?:[^*/][^*]*\*+)*
/
)
)
Захват квотированной строки (PCRE):
'(?>[^\\']+|''|\\.)*'
Захват квотированного названия объекта БД (PCRE):
(?>"(?>[^\\"]+|""|\\.)*"|`(?>[^\\`]+|``|\\.)*`)
Захват комментариев (PCRE):
(?>
#singe-line comment
-- [^\r\n]*+
|
#multi-line comment by Jeffrey Friedl (fastest)
/\*
[^*]* \*+
(?:[^*/][^*]*\*+)*
/
)
- Валидация (неполная, но быстрая) регулярного выражения на диалект ECMA 262 (JavaScript), есть проверка на уникальность флагов: PCRE
Регулярное выражение: PCRE
Пароль должен соответствовать следующим требованиям:
- длина от 8 до 72 символов (72 символа — это ограничение алгоритма bf)
- допускаются только цифры, английские буквы и знаки пунктуации
- содержит хотябы одну цифру (0-9)
- содержит хотябы одну английскую прописную букву (A-Z)
- содержит хотябы одну английскую строчную букву (a-z)
- содержит хотябы один знак пунктуации:
!"#$%&'()*+,-./:;<=>?@[\]^_``{|}~
- не имеют 6 и более подряд совпадающих символов типа "zzzzzz", "000000"
- не имеет "плохих" последовательностей типа "123456", "abcdef", "qwerty"
- Захват только непустых значений колонок: PCRE
- Как распарсить CSV строку в таблицу? PCRE, PostgreSQL
Ищем до первого найденного управляющего символа по регулярному выражению /[\x00-\x1f](?<![\x08\x09\x0c\x0a\x0d])/
(одинаково в диалектах PCRE и JS)
JSON не должен определяться как бинарный, поэтому исключаем все специальные символы по спецификации:
\b
represents the backspace characterU+0008
\t
represents the character tabulation characterU+0009
\f
represents the form feed characterU+000C
\n
represents the line feed characterU+000A
\r
represents the carriage return characterU+000D