У вас есть форма на сайте или диалоговое окно в приложении, которое запрашивает у пользователя адрес электронной почты. Вы хотите использовать регулярное выражение для проверки этого адреса электронной почты перед попыткой отправить на него письмо. Это уменьшит количество писем, возвращаемых вам как недоставленные.
Простой
Это первое решение выполняет очень простую проверку. Оно проверяет только наличие в строке знака at (@), которому предшествует и за которым следует один или несколько символов, не являющихся пробелами.
1 | ^\S+@\S+$ |
1 | \A\S+@\S+\Z |
Простое, с ограничениями на символы
Доменное имя, часть после знака @, ограничено символами, разрешены в доменных именах. Интернационализированные доменные имена не допускаются. Локальная часть, часть перед знаком @, ограничена символами, обычно используемыми в локальных частях электронной почты, что является более строгим ограничением, чем то, которое принимают большинство почтовых клиентов и серверов:
Параметры регекса: Без учета регистра
1 | ^[A-Z0-9+_.-]+@[A-Z0-9.-]+$ |
1 | \A[A-Z0-9+_.-]+@[A-Z0-9.-]+\Z |
Простое, со всеми допустимыми символами локальной части
Это регулярное выражение расширяет предыдущее, позволяя использовать в локальной части больший набор редко используемых символов. Не все почтовые программы могут работать со всеми этими символами, но мы включили все символы, разрешенные RFC 5322, который регулирует формат почтовых сообщений. Среди разрешенных символов есть и такие, которые представляют угрозу безопасности, если передаются непосредственно из пользовательского ввода в оператор SQL, например одинарная кавычка (') и символ трубы (|). Обязательно экранируйте чувствительные символы при вставке адреса электронной почты в строку, передаваемую другой программе, чтобы предотвратить такие бреши в безопасности, как атаки SQL-инъекций:
Параметры регекса: Без учета регистра
1 | ^[A-Z0-9_!#$%&'*+/=?`{|}~^.-]+@[A-Z0-9.-]+$ |
1 | \A[A-Z0-9_!#$%&'*+/=?`{|}~^.-]+@[A-Z0-9.-]+\Z |
Отсутствие передних, задних или последовательных точек
Как локальная часть, так и доменное имя могут содержать одну или несколько точек, но две точки не могут располагаться рядом друг с другом. Кроме того, первый и последний символы в локальной части и в доменном имени не должны быть точками:
Параметры регекса: Без учета регистра
1 | ^[A-Z0-9_!#$%&'*+/=?`{|}~^-]+(?:\.[A-Z0-9_!#$%&'*+/=?`{|}~^-]+)*@[A-Z0-9-]+(?:\.[A-Z0-9-]+)*$ |
1 | \A[A-Z0-9_!#$%&'*+/=?`{|}~^-]+(?:\.[A-Z0-9_!#$%&'*+/=?`{|}~^-]+)*@[A-Z0-9-]+(?:\.[A-Z0-9-]+)*\Z |
Домен верхнего уровня содержит от двух до шести букв
Это регулярное выражение дополняет предыдущие версии, указывая, что доменное имя должно содержать как минимум одну точку, а часть доменного имени после последней точки может состоять только из букв. То есть домен должен содержать как минимум два уровня, например secondlevel.com или thirdlevel.secondlevel.com.Домен верхнего уровня (.com в этих примерах) должен состоять из двух-шести букв. Все домены верхнего уровня с кодом страны (.us, .uk и т. д.) состоят из двух букв. Родовые домены верхнего уровня содержат от трех (.com) до шести букв (.museum):
Параметры регекса: Без учета регистра
1 | ^[\w!#$%&'*+/=?`{|}~^-]+(?:\.[\w!#$%&'*+/=?`{|}~^-]+)*@(?:[A-Z0-9-]+\.)+[A-Z]{2,6}$ |
1 | \A[\w!#$%&'*+/=?`{|}~^-]+(?:\.[\w!#$%&'*+/=?`{|}~^-]+)*@(?:[A-Z0-9-]+\.)+[A-Z]{2,6}\Z |
Об адресах электронной почты
Если вы думали, что для такой концептуально простой вещи, как проверка адреса электронной почты, найдется простое универсальное решение в виде regex, то вы сильно ошибались. Этот пример - яркий пример того, что прежде чем приступить к написанию регулярного выражения, нужно точно решить, что именно вы хотите сопоставить. Не существует общепринятого правила о том, какие адреса электронной почты являются действительными, а какие нет. Это зависит от вашего определения понятия «действительный».
Адрес [email protected] является действительным в соответствии с RFC 5322, который определяет синтаксис для адресов электронной почты. Но он не действителен, если в вашем определении указано, что действительный адрес электронной почты - это тот, который принимает почту. Домена верхнего уровня asdf не существует.
Короткий ответ на проблему валидности заключается в том, что вы не можете знать, является ли [email protected] адресом электронной почты, который действительно может принимать почту, пока не попытаетесь отправить на него письмо. И даже тогда вы не можете быть уверены, сигнализирует ли отсутствие ответа о том, что домен somewhere.com молча отбрасывает почту, отправленную на несуществующие почтовые ящики, или что Джон Доу нажал кнопку Delete на своей клавиатуре, или что его спам-фильтр опередил его.
Поскольку в конечном итоге вам придется проверять, существует ли адрес, отправляя на него почту, вы можете выбрать более простое или более спокойное регулярное выражение. Допускать пропуск недействительных адресов может быть предпочтительнее, чем раздражать людей, блокируя действительные адреса. По этой причине вы можете выбрать «простое» регулярное выражение. Несмотря на то, что оно допускает многие вещи, которые не являются адресами электронной почты, например #$%@.-, это выражение быстрое и простое, и оно никогда не заблокирует действительный адрес электронной почты.
Если вы хотите избежать отправки большого количества недоставленных писем, но при этом не блокировать реальные адреса электронной почты, хорошим выбором будет использование regex в домене верхнего уровня, состоящем из двух-шести букв.
Необходимо учитывать, насколько сложным должно быть регулярное выражение. Если вы проверяете вводимые пользователем данные, вам, скорее всего, понадобится более сложный регекс, поскольку пользователь может ввести что угодно. Но если вы сканируете файлы базы данных, которые, как вы знаете, содержат только правильные адреса электронной почты, вы можете использовать очень простой регекс, который просто отделит адреса электронной почты от других данных. В этом случае может быть достаточно даже решения из предыдущего подраздела.
Наконец, необходимо подумать о том, насколько перспективным вы хотите видеть ваше регулярное выражение. В прошлом имело смысл ограничить домен верхнего уровня только двухбуквенными комбинациями для кодов стран и исчерпывающим списком общих доменов верхнего уровня, то есть 'com|net|org|mil|edu'. Сейчас, когда постоянно добавляются новые домены верхнего уровня, такие регулярные выражения быстро устаревают.
Синтаксис регулярных выражений
Регулярные выражения, представленные в этом рецепте, демонстрируют все основные части синтаксиса регулярных выражений в действии.
Все регулярные выражения, кроме «простого», требуют включения опции сопоставления без учета регистра. В противном случае будут разрешены только символы в верхнем регистре. Включение этой опции позволяет набирать '[A-Z]' вместо '[A-Za-z]', что экономит несколько нажатий клавиш.
- '\S' - это сокращенный класс символов, как объясняется в рецепте 2.3. '\S' соответствует любому символу, который не является символом пробела.
- '@' и '\.' соответствуют буквальному знаку @ и точке, соответственно. Поскольку точка является метасимволом, используемым вне классов символов, она должна быть экранирована обратным слешем. Знак @ не имеет специального значения ни в одном из описанных в этой книге вариантов регулярных выражений. В рецепте 2.1 приведен список всех метасимволов, которые необходимо экранировать.
- '[A-Z0-9.-]' и другие последовательности между квадратными скобками - это классы символов. Этот класс позволяет использовать все буквы от A до Z, все цифры от 0 до 9, а также литеральную точку и дефис. Хотя дефис обычно создает диапазон в классе символов, дефис рассматривается как литерал, когда он встречается в качестве первого или последнего символа в классе символов. В рецепте 2.3 рассказывается о классах символов, в том числе об их сочетании со скороговорками, как в '[A-Z0-9_!#$%&'*+/=?`{|}~^.-]'. Этот класс соответствует символу слова, а также любому из 19 перечисленных знаков препинания.
- '+' и '*', используемые вне классов символов, являются квантификаторами. Знак плюс повторяет предыдущую лексему регекса один или более раз, а звездочка повторяет ее ноль или более раз. В таких регулярных выражениях квантифицируемая лексема обычно представляет собой класс символов, а иногда и группу. Поэтому '[A-Z0-9.-]+' соответствует одной или нескольким буквам, цифрам, точкам и/или дефисам.
В качестве примера использования группы, '(?:[A-Z0-9-]+\.)+' соответствует одной или нескольким буквам, цифрам и/или дефисам, за которыми следует одна литеральная точка. Знак плюс повторяет эту группу один или несколько раз. Группа должна совпасть хотя бы один раз, но может совпадать столько раз, сколько возможно.
'(?:⋯)' - это не захватывающий
Проблема с '^' и '$' в сравнении с '\A' и '\Z' применима ко всем регулярным выражениям, проверяющим вводимые данные. Если вы используете Ruby, не забывайте использовать '\A' и '\Z', если хотите избежать совпадения одной строки в многострочной строке.
Построение регулярного выражения шаг за шагом
Этот пример иллюстрирует, как можно построить регулярное выражение шаг за шагом. Эта техника особенно удобна при использовании интерактивного тестера регулярных выражений, такого как RegexBuddy.
Сначала загрузите в инструмент кучу валидных и невалидных образцов данных. В данном случае это будет список действительных адресов электронной почты и список недействительных адресов электронной почты.
Затем напишите простое регулярное выражение, которое будет соответствовать всем действительным адресам электронной почты. Недействительные адреса пока проигнорируйте. '^\S+@\S+$' уже определяет базовую структуру адреса электронной почты: локальная часть, знак at и доменное имя.
Определив основную структуру текстового шаблона, вы можете уточнять каждую часть до тех пор, пока ваше регулярное выражение не перестанет соответствовать недопустимым данным. Если ваше регулярное выражение должно работать только с ранее существующими данными, это может быть быстрой работой. Если же регулярное выражение должно работать с любым пользовательским вводом, то редактировать его до тех пор, пока оно не станет достаточно ограничительным, будет гораздо сложнее, чем просто заставить его соответствовать допустимым данным.
Вариации
Если вы хотите искать адреса электронной почты в больших массивах текста, а не проверять, является ли вводимый текст в целом адресом электронной почты, вы не можете использовать якоря '^' и '$'. Простое удаление якорей из регулярного выражения не является правильным решением. Если так поступить с последним regex, который ограничивает домен верхнего уровня буквами, то он будет соответствовать, например, [email protected] в [email protected]. Вместо того чтобы привязывать регекс к началу и концу темы, нужно указать, что начало локальной части и домен верхнего уровня не могут быть частью более длинных слов.
Это легко сделать с помощью пары границ слов. Замените оба символа '^' и '$' на '\b'. Например, '^[A-Z0-9+_.-]+@[A-Z0-9.-]+$' превращается в '\b[A-Z0-9+_.-]+@[A-Z0-9.-]+\b'.
См. также
RFC 5322 определяет структуру и синтаксис сообщений электронной почты, включая адреса электронной почты, используемые в сообщениях электронной почты. Вы можете загрузить RFC 5322 по адресу http://www.ietf.org/html/rfc5322.txt.
Википедия содержит полный список доменных имен верхнего уровня по адресу http://en.wikipedia.org/wiki/List_of_Internet_top-level_domains.