Как найти или проверить e-mail адрес

в 18:26, , рубрики: e-mail, regexp, regular expressions, Регулярные выражения

Наибольшее число отзывов, не говоря уже об «ошибках», мне приходит на регулярное выражение e-mail адреса:

b[A-Z0-9._%+-]+@[A-Z0-9.-]+.[A-Z]{2,4}b

Я утверждаю, что это регулярное выражение определяет любой e-mail адрес. В обратной связи обычно показывается один e-mail адрес, который не подпадает под это выражение; также, в отчетах об «ошибках» содержится предложение создать идеальный regexp.

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

  • перед написание выражения вы должны точно знать, что должно совпасть, а что нет;
  • следует разрешить компромисс между точностью и практичностью.


Достоинство моего регулярного выражения в том, что оно определяет 99% e-mail адресов, используемых сегодня. Все полученные адреса могут быть обработаны 99% почтовых программ. Если вы ищете быстрое решение, то вам будет достаточно прочитать лишь следующий параграф.

Если вы хотите использовать регулярное выражение, написанное выше, нужно понимать две вещи. Во-первых, большое регулярное выражение затрудняет красивое форматирование абзацев. Поэтому я не использую "a-z" ни в одном из трех классов символов. Для этого в настройках вашей программы должна быть отключена опция проверки регистра. (Вы удивитесь, как много отчетов об «ошибках» я получаю по этому поводу.) Во вторых, регулярное выражение выше разделено границами слов, что делает его пригодным для извлечения e-mail адресов из файлов или больших блоков текста. Если вы хотите проверить, является ли введенный пользователем текст действительным адресом электронной почты, замените разделители слов на якори начала и конца строки, например так:

^[A-Z0-9._%+-]+@[A-Z0-9.-]+.[A-Z]{2,4}$

Компромиссы в подтверждении e-mail адреса

Да, есть целая куча адресов электронной почты, которую не находит моё регулярное выражение. Наиболее цитируемыми адресами являются те, которые имеют домен верхнего уровня .museum, который длиннее, чем разрешенные для него 4 символа. Я принимаю этот компромисс, потому что число людей, использующих этот домен верхнего уровня, крайне невелико. Мне никогда не поступали жалобы, что формы заказа или подписки на новости на сайтах моей компании отказались использовать адрес с .museum.

Чтобы включить .museum, вы можете использовать такое выражение:

^[A-Z0-9._%+-]+@[A-Z0-9.-]+.[A-Z]{2,6}$

Но это другой компромисс. Это выражение будет находить адрес john@mail.office. Гораздо более вероятно, что Джон забыл указать .com в конце адреса, чем то, что он создал домен верхнего уровня .office без разрешения ICANN.

Пример выше показывает и другой компромисс: вы хотите, чтобы регулярное выражение проверяло, существует ли домен верхнего уровня? Моё регулярное выражение этого не делает. Любая комбинация из двух — четырех символов охватит все существующие (и планируемые) домены верхнего уровня, за исключением .museum [и .travel — прим. пер.] Но она будет определять недействительные e-mail адреса вида asdf@asdf.asdf. Не будучи чрезвычайно строгим к домену верхнего уровня, мне не придется обновлять регулярные выражения всякий раз, когда будет создаваться очередной домен.

^[A-Z0-9._%+-]+@[A-Z0-9.-]+.(?:[A-Z]{2}|com|org|net|edu|gov|mil|biz|info|mobi|name|aero|asia|jobs|museum)$

Это регулярное выражение может быть использовано для любых двухбуквенных кодов страны и только конкретных общих доменов верхнего уровня. На текущий момент этот список может быть уже устаревшим. Я рекомендую сохранить этот список как глобальную константу в вашем приложении, чтобы вам пришлось обновлять его только в одном месте. Вы также можете перечислить все коды стран, хотя их уже насчитывается порядка двухсот.

E-mail адрес также может быть зарегистрирован на субдомене, например john@mail.company.com. Все регулярные выражения выше будут определять этот адрес, поскольку я добавил символ "." в класс символов, следующий за @. Но они также будут определять john@aol...com, что неверно. Вы можете исключить такие случаи, заменив "[A-Z0-9.-]+." на "(?:[A-Z0-9-]+.)+". Я убрал точку из класса символов и вместо этого повторил этот класс и символ точки. Например,

b[A-Z0-9._%+-]+@(?:[A-Z0-9-]+.)+[A-Z]{2,4}b

будет определять john@server.department.company.com, но не john@aol...com.

Другим компромиссом является то, что мои регулярные выражения позволяют только латинские буквы, цифры и некоторые специальные символы. Основная причина этого в том, что я не совсем уверен в том, что мое почтовое обеспечение могло бы справиться с остальными символами. Даже если John.O'Hara@theoharas.com — это синтаксически правильный e-mail адрес, существует опасность, что некоторые почтовые программы расценят апостроф как разделитель цитат. Например, слепая вставка этого адреса в SQL приведет к сбою, если строки разделяются одинарными кавычками. И, конечно, уже много лет домены могут содержать не латинские символы. Большинство программ и даже доменных регистраторов однако до сих пор придерживаются тех 37 символов, к которым они привыкли.

Вывод таков: чтобы решить, какое регулярное выражение использовать, неважно, собираетесь ли вы находить e-mail адрес или что-либо ещё точно определенное, вы должны начать с учета всех компромиссов. Насколько плохо то, что найденное не соответствует действительному? Насколько плохо то, что что-то действительное не находится? Насколько сложным может быть ваше регулярное выражение? В какую цену вам обошлось бы изменение этого выражения впоследствии? Различные ответы на эти вопросы требуют различных регулярных выражений в качестве решения. Мои регулярные выражения делают то, что я хочу, но они могут не делать того, чего вы бы хотели.

Регулярные выражения не отправляют e-mail

Не переусердствуйте в ваших попытках устранить недействительные адреса электронной почты в вашем регулярном выражении. Если вам нужно разрешить .museum, часто лучше разрешить все шестисимвольные домены верхнего уровня, чем перечислять все текущие домены. Причина в том, что вы действительно не узнаете, является ли данный e-mail адрес действительным, пока не попытаетесь отправить на него письмо. И даже этого может быть недостаточно. Даже если письмо приходит в почтовый ящик, это еще не значит, что его кто-то прочтет.

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

Официальный стандарт: RFC 2822

Может быть, вам интересно, почему нет «официального» надежного регулярного выражения для нахождения адресов электронной почты? Ну что ж, вот официальное определение, но оно едва ли надежное.

Официальный стандарт известен как RFC 2822. Он описывает синтаксис, которого действительные e-mail адреса должны придерживаться. Вы можете (но не должны) реализовать его следующим регулярным выражением:

(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[x01-x08x0bx0cx0e-x1fx21x23-x5bx5d-x7f]|\[x01-x09x0bx0cx0e-x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[x01-x08x0bx0cx0e-x1fx21-x5ax53-x7f]|\[x01-x09x0bx0cx0e-x7f])+)])

Это регулярное выражение состоит из двух частей: часть до @, и часть после символа @. Есть два варианта части перед @: она может состоять из ряда букв, цифр и некоторых символов, включая одну или несколько точек. Тем не менее, точки не могут появляться последовательно, в начале или конце адреса электронной почты. Другая альтернатива требует, чтобы часть до @ была заключена в двойные кавычки, позволяющие любой строке ASCII символов находиться между кавычками. Пробельные символы, двойные кавычки и обратные слеши должны начинаться с обратной косой черты.

Часть после @ также имеет две альтернативы. Это может быть либо полное доменное имя (например, example.com), либо буквальный адрес в Интернете в квадратных скобках. Буквальным адресом в Интернете может быть IP-адрес или предметно-ориентированный адрес маршрутизации.

Причина, по которой вы не должны использовать это регулярное выражение, в том, что он проверяет только базовый синтаксис адреса электронной почты. john@aol.com.nospam будет считаться действительным адресом электронной почты в соответствии с RFC 2822. Очевидно, что этот адрес электронной почты не будет работать, так как нет никакого .nospam домена верхнего уровня. Он также не гарантирует, что ваша почтовая программа сможет справиться с этим. Не все приложения поддерживают синтаксис, использующий двойные кавычки или квадратные скобки. На самом деле, RFC 2822 сам отмечает использование квадратных скобок как устаревшее.

Мы получим более практическую реализацию RFC 2822, если опустим части, где используются двойные кавычки и квадратные скобки. Он по-прежнему соответствует 99,99% всех адресов электронной почты, находящихся в фактическом использовании.

[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?

Дальнейшее изменение, которое вы могли бы сделать, — это разрешить любые двухбуквенные коды страны доменов верхнего уровня, и только конкретные общие домены верхнего уровня. Это регулярное выражение фильтрует такие фиктивные адреса электронной почты, как asdf@adsf.adsf. Вам нужно будет обновлять его по мере добавления новых доменов верхнего уровня.

[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?.)+(?:[A-Z]{2}|com|org|net|edu|gov|mil|biz|info|mobi|name|aero|asia|jobs|museum)b

Так что даже после следования официальным стандартам, компромиссы всё ещё остались. Не стоит слепо копировать регулярные выражения из интернет-библиотек или форумов. Всегда проверяйте их на собственных данных и с вашими собственными приложениями.

Автор: Witold

Источник

Поделиться

* - обязательные к заполнению поля