Как проверять email адрес на валидность правильно

Предположим, у вас есть простая задача — создать форму, которая даст пользователю возможность подписаться на e-mail оповещения. Разумеется, вам необходимо предотвратить ввод в эту форму всякого мусора, при этом не должно получаться так, чтобы валидный адрес вдруг был забракован системой.

Как же выглядит e-mail адрес? Интуитивно можно предположить, что так:

Выглядит хорошо, но это совершенно не тот случай, когда стоит доверять интуиции. Доверять следует спецификации. А спецификация говорит нам следующее:

Конечно, и тут можно обойтись с помощью регулярного выражения:

Но с этим есть несколько проблем:

  • Как вы будете проверять правильность этого монстра? Такие регулярные выражения переходят «из уст в уста» на форумах, и каждый добавляет в них функциональность до тех пор, пока работа с выражением становится невозможной. И это именно тот случай.
  • Я бы не сказал, что регулярные выражения такой длины эффективнее, чем другие методы. Чем длиннее выражение, тем дольше оно будет компилироваться (сравнение всегда происходит за O(n)).
  • С помощью регулярного выражения можно сделать только проверку на соответствие. Выполнить проверку на то, находится ли домен в чёрном списке, у вас уже, увы, не получится.

Давайте пойдём другим путём

Вот основа нашей проверки:

А вот диаграмма, описывающая алгоритм, по которому наша программа будет работать:

emailaddrfsm

Если вы заметили, что тут не все правила соблюдаются — не волнуйтесь, мы вернёмся к этому позже. Если вы не заметили, и вообще не понимаете, что тут происходит, то сейчас объясню.

Вершина графа — состояние проверки. Ребро графа — прочитанный символ. Если в результате считывания символа невозможно перейти ни по одному ребру, значит, адрес не валиден. Вот, например, как будет реализована первая часть этого алгоритма:

simplecountingfsm

Теперь о проверках, которые мы сделаем, после того, как код пройдёт по этой диаграмме:

Собираем всё вместе

Перевод статьи «Validating Email Addresses with a Regex? Do yourself a favor and don’t»