Регулярные выражения на практике: телефоны, email и URL
Практика3 минРедакция Innovialabs
Коротко
Регулярка подходит для проверки формата, а не существования: телефон лучше нормализовать до цифр и проверить шаблоном, email — простым шаблоном плюс письмо-подтверждение, URL — встроенным парсером.
Короткий ответ
Регулярное выражение отвечает только на вопрос «похоже ли это на телефон, email или ссылку». Оно не скажет, существует ли номер, доходят ли письма и открывается ли сайт. Поэтому рабочая схема такая:
- Нормализовать ввод — убрать пробелы, скобки, дефисы.
- Проверить формат простым и понятным шаблоном.
- Подтвердить реальность — SMS-код, письмо со ссылкой, запрос к сайту.
- Повторить проверку на сервере: клиентскую валидацию легко обойти.
Телефоны Узбекистана (+998)
Номер в Узбекистане — это код страны 998 и ещё 9 цифр: двухзначный код оператора или региона и семь цифр абонента. Люди вводят его по-разному: +998 90 123 45 67, 998901234567, (90) 123-45-67.
Надёжнее всего сначала оставить только цифры, а уже потом проверять:
function normalizeUzPhone(input) {
const digits = input.replace(/\D/g, "");
if (/^998\d{9}$/.test(digits)) return "+" + digits;
if (/^\d{9}$/.test(digits)) return "+998" + digits;
return null;
}
normalizeUzPhone("(90) 123-45-67"); // "+998901234567"
normalizeUzPhone("12345"); // null
Если нужно проверить номер «как ввёл пользователь», без нормализации, подойдёт такой шаблон:
^(?:\+?998)?[\s-]?\(?\d{2}\)?[\s-]?\d{3}[\s-]?\d{2}[\s-]?\d{2}$
Храните номер в одном формате — +998XXXXXXXXX (E.164). Так проще искать дубликаты и передавать номер в SMS-шлюзы и CRM.
Не зашивайте список кодов операторов в регулярку: коды добавляются, и форма начнёт отклонять настоящие номера. Если проверка кодов действительно нужна, держите список в конфигурации.
Полный стандарт адреса электронной почты настолько сложен, что «идеальная» регулярка получается нечитаемой и всё равно не гарантирует доставку. На практике хватает простого шаблона:
const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
EMAIL_RE.test("user@example.com"); // true
EMAIL_RE.test("user@localhost"); // false
EMAIL_RE.test("user @mail.com"); // false
Он ловит опечатки — пропущенный @, пробелы, отсутствие домена — и не отсекает редкие, но допустимые адреса с +, дефисами или поддоменами. Существование ящика проверяется только письмом с подтверждением.
Типичная ошибка — слишком строгий шаблон вроде [a-z0-9.]+@[a-z]+\.[a-z]{2,3}. Он отклоняет адреса с +, домены из нескольких уровней и длинные доменные зоны.
URL
Для ссылок регулярка — плохой инструмент: у URL много частей, кодировок и крайних случаев. Используйте встроенный парсер и проверьте протокол:
function isHttpUrl(value) {
try {
const url = new URL(value);
return url.protocol === "http:" || url.protocol === "https:";
} catch {
return false;
}
}
Проверка протокола важна: без неё пройдут ссылки вида javascript:..., опасные для вставки в страницу. Если вы делаете редирект по ссылке из параметра, сверяйте url.hostname со списком разрешённых доменов.
Чтобы просто найти ссылки в тексте, например в сообщении чат-бота, достаточно грубого шаблона https?://[^\s<>"]+.
Где регулярки не справляются
- Существование: номер, ящик и сайт могут быть корректными по формату, но не работать.
- Международные адреса: домены и email на кириллице или других алфавитах часто не проходят ASCII-шаблоны.
- Бизнес-правила: «только мобильные номера» или «только корпоративная почта» лучше проверять кодом, а не усложнять шаблон.
- Безопасность: регулярка не защищает от XSS и SQL-инъекций — для этого нужно экранирование и параметризованные запросы.
Катастрофический бэктрекинг
Некоторые шаблоны на неудачной строке работают экспоненциально долго и могут заблокировать сервер. Классический пример:
^([a-z0-9]+\.?)+@
Вложенный квантификатор и необязательная точка позволяют разбить одну и ту же строку букв множеством способов. На длинной строке без @ движок перебирает их все.
Как защититься:
- Не вкладывайте квантификаторы над одними и теми же символами. Безопасная версия того же шаблона —
^[a-z0-9]+(?:\.[a-z0-9]+)*@: каждое повторение обязано начинаться с точки. - Ограничивайте длину ввода до запуска регулярки.
- Проверяйте шаблоны на длинных «почти подходящих» строках в тестах.
- Там, где шаблоны приходят извне, используйте движки с линейной сложностью, например RE2 или стандартный пакет
regexpв Go.