В этой статье рассмотривается валидация email изпользуя регулярные выражения. Все регэкспы выполняются с модификатором
Перед тем как писать валидацию, надо знать из чего состоит email адрес. Думаю известно всем что это «username@hostname». Лучше всего будет разбить создание регэкспа на 2 логические части — валидация hostname и валидация username. Начнём с более объёмного.
Для начала подумаем, а из чего же состоит hostname?
Имя хоста состоит из нескольких компонентов, разделённых точкой и не превышающих 63 символа, и суффиксов (домены первого уровня). Компоненты, в свою очередь, состоят из латинских букв, цифр и дефисов, причём дефисы не могут быть в начале или в конце компонента. Суффиксы это ограниченный список доменов первого уровня (я нашёл список на сайте IANA). Для упрощения выражения запишем домены стран как
Для компонентов код будет посложнее:
Разберём выражение:
Рассмотрим необязательную часть:
В итоге мы получили выражение отвечающее за проверку hostname:
Обращу внимание на то, что присутствие компонентов не обязательно, т.к. некоторые домены первого уровня поддерживаются серверами. Пример.
Имя пользователя может в себе содержать:
Приведу сразу выражение:
На самом деле тут все просто: 1 или более символ
Регэксп проверки email:
Это выражение можно каплю оптимизировать (про оптимизацию, я думаю, будет отдельная статья):
Рассмотрим регэксп, который привели в пример в комментарии к вступительному топику:
Какие тут есть главные проблемы?
P.S. Пишите о багах и пожеланиях — обязательно исправлю.
P.P.S. По желанию могу выложить функцию проверки email, используюмую мной.
i
, т.е. делают регистронезависимую проверку.Подготовка
Перед тем как писать валидацию, надо знать из чего состоит email адрес. Думаю известно всем что это «username@hostname». Лучше всего будет разбить создание регэкспа на 2 логические части — валидация hostname и валидация username. Начнём с более объёмного.
Валидация hostname
Для начала подумаем, а из чего же состоит hostname?
Имя хоста состоит из нескольких компонентов, разделённых точкой и не превышающих 63 символа, и суффиксов (домены первого уровня). Компоненты, в свою очередь, состоят из латинских букв, цифр и дефисов, причём дефисы не могут быть в начале или в конце компонента. Суффиксы это ограниченный список доменов первого уровня (я нашёл список на сайте IANA). Для упрощения выражения запишем домены стран как
[a-z][a-z]
(любые 2 символа от a до z не зависимо от регистра). Так же не будем использовать не латинские символы, пока они официально не введены в публичное пользование. В итоге получим выражение проверяющее суффикс (конструкция (foo|bar)
говорит о том что происходит поиск либо foo либо bar, т.е. заменяет или):(aero|arpa|asia|biz|cat|com|coop|edu|gov|info|int|jobs|mil|mobi|museum|name|net|org|pro|tel|travel|[a-z][a-z])
Для компонентов код будет посложнее:
([a-z0-9]([-a-z0-9]{0,61}[a-z0-9])?\.)
Разберём выражение:
[a-z0-9] # обязательная буква латинского алфавита или цифра
([-a-z0-9]{0,61}[a-z0-9])? # необязательная часть
\. # точка
Рассмотрим необязательную часть:
# дефис ставиться на первое место в группе символов, иначе он принимается за промежуток
# {0,61} после группы символов означает, что группа может повторятся от 0 до 61 раза
[-a-z0-9]{0,61}
# 61 для того, чтобы в группе не было более 63 символов в сумме
[a-z0-9]
В итоге мы получили выражение отвечающее за проверку hostname:
([a-z0-9]([-a-z0-9]{0,61}[a-z0-9])?\.)*(aero|arpa|asia|biz|cat|com|coop|edu|gov|info|int|jobs|mil|mobi|museum|name|net|org|pro|tel|travel|[a-z][a-z])
Обращу внимание на то, что присутствие компонентов не обязательно, т.к. некоторые домены первого уровня поддерживаются серверами. Пример.
Валидация username
Имя пользователя может в себе содержать:
- латиницу
- цифры
- знаки! # $ % & ' * + — / =? ^ _ ` { | } ~
- точку, за исключением первого и последнего знака, которая не может повторятся
Приведу сразу выражение:
[-a-z0-9!#$%&'*+/=?^_`{|}~]+(\.[-a-z0-9!#$%&'*+/=?^_`{|}~]+)*
На самом деле тут все просто: 1 или более символ
[-a-z0-9!#$%&'*+/=?^_`{|}~]
, далее 0 или больше компонентов \.[-a-z0-9!#$%&'*+/=?^_`{|}~]+
.В итоге
Регэксп проверки email:
^[-a-z0-9!#$%&'*+/=?^_`{|}~]+(\.[-a-z0-9!#$%&'*+/=?^_`{|}~]+)*@([a-z0-9]([-a-z0-9]{0,61}[a-z0-9])?\.)*(aero|arpa|asia|biz|cat|com|coop|edu|gov|info|int|jobs|mil|mobi|museum|name|net|org|pro|tel|travel|[a-z][a-z])$
Это выражение можно каплю оптимизировать (про оптимизацию, я думаю, будет отдельная статья):
^[-a-z0-9!#$%&'*+/=?^_`{|}~]+(?:\.[-a-z0-9!#$%&'*+/=?^_`{|}~]+)*@(?:[a-z0-9]([-a-z0-9]{0,61}[a-z0-9])?\.)*(?:aero|arpa|asia|biz|cat|com|coop|edu|gov|info|int|jobs|mil|mobi|museum|name|net|org|pro|tel|travel|[a-z][a-z])$
Бонус
Рассмотрим регэксп, который привели в пример в комментарии к вступительному топику:
^(\S+)@([a-z0-9-]+)(\.)([a-z]{2,4})(\.?)([a-z]{0,4})+$
Какие тут есть главные проблемы?
- Так как username может состоять из любых символов кроме пробелов, username "日本国" является валидным.
- Домен первого уровня может состоять из любых 4 латинских букв, например .habr
- Ужасная проверка домена: 1 или более символов, обязательная точка, 2-4 обязательных символа, необязательная точка, 0-4 символа в прибавок. Причём каждый из этих блоков сохраняется в память.
P.S. Пишите о багах и пожеланиях — обязательно исправлю.
P.P.S. По желанию могу выложить функцию проверки email, используюмую мной.