Python: проверяем адреса электронной почты с помощью регулярных выражений

Вступление

Регулярные выражения – это выражения шаблонов, которые можно использовать для текстового поиска и замены действий, проверок, разделения строк и многого другого. Эти шаблоны состоят из символов, цифр и специальных символов так, чтобы шаблон соответствовал определенным сегментам текста, которые мы просматриваем.

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

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

Универсальное регулярное выражение для электронной почты

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

Нужно определить, какой формат адреса электронной почты мы ищем. Наиболее распространённый формат:

(username)@(domainname).(top-leveldomain)

Таким образом, мы можем свести это к шаблону символа @, отделяющего префикс от сегмента домена.

Префикс – имя получателя, строка, которая может содержать прописные и строчные буквы, цифры и некоторые специальные символы: точка, дефис, подчёркивание.

Домен состоит из его имени и домена верхнего уровня, разделённых точкой. Доменное имя может содержать прописные и строчные буквы, цифры и символы (дефис). Кроме того, доменное имя верхнего уровня должно содержать не менее 2 символов (все прописные или строчные буквы), но может быть длиннее.

Проще говоря, наше регулярное выражение электронной почты может выглядеть следующим образом:

(string1)@(string2).(2+characters)

Сюда подходят следующие адреса:

name.surname@gmail.com
anonymous123@yahoo.co.uk
my_email@outlook.co

Опять-таки, используя то же выражение, эти адреса работать не будут:

johnsnow@gmail
anonymous123@...uk
myemail@outlook.

Стоит отметить, что строки не должны содержать определенных специальных символов, чтобы они не нарушили форму. Кроме того, домен верхнего уровня не может быть Мы можем изложить эти правила в конкретном выражении:

([A-Za-z0-9]+[.-_])*[A-Za-z0-9]+@[A-Za-z0-9-]+(\.[A-Z|a-z]{2,})+

Специальный символ в префиксе не может стоять перед символом @, а префикс не может начинаться с него, поэтому нужно убедиться, что до и после каждого специального символа есть по крайней мере один буквенно-цифровой символ.

Электронное письмо может содержать несколько доменов верхнего уровня, разделенных точкой.

Очевидно, что это регулярное выражение сложнее первого, но оно охватывает все правила, которые мы определили для формата электронной почты. Опять же, это, вероятно, не сможет исключить некоторые крайние случаи, о которых мы не подумали.

Проверяем адрес электронной почты с помощью Python

Модуль re содержит классы и методы для представления и работы с регулярными выражениями в Python, поэтому мы импортируем его в наш скрипт. Мы будем использовать метод re.fullmatch(pattern, string, flags). Этот метод возвращает объект соответствия только в том случае, если вся строка соответствует шаблону, в любом другом случае он не возвращает ни одного.

Давайте скомпилируем регулярное выражение и определим простую функцию, которая принимает адрес электронной почты и использует выражение для его проверки:

import re

regex = re.compile(r'([A-Za-z0-9]+[.-_])*[A-Za-z0-9]+@[A-Za-z0-9-]+(\.[A-Z|a-z]{2,})+')

def isValid(email):
    if re.fullmatch(regex, email):
      print("Valid email")
    else:
      print("Invalid email")

Метод re.compile() компилирует шаблон регулярного выражения в объект регулярного выражения. В основном он используется из-за эффективности, когда мы планируем сопоставлять шаблон более одного раза.

Теперь протестируем код на некоторых примерах, которые мы рассмотрели ранее:

isValid("name.surname@gmail.com")
isValid("anonymous123@yahoo.co.uk")
isValid("anonymous123@...uk")
isValid("...@domain.us")

Результат:

Valid email
Valid email
Invalid email
Invalid email

Класс, система работает!

Более крутое регулярное выражение для проверки

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

Длинные выражения, как правило, становятся немного запутанными и трудными для чтения, и это выражение не является исключением:

(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=^_`{|}~-]+)*
|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]
|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")
@
(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?
|\[(?:(?:(2(5[0-5]|[0-4][0-9])
|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])
|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]
|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])

Это регулярное выражение, совместимое с RFC5322, которое охватывает 99,99 % входных адресов электронной почты. Вот как оно работает:

На самом деле это не единственное выражение, которое удовлетворяет RFC5322. Более короткую версию, которая соответствует нашим требованиям, можно импортировать в метод re.compile():

import re

regex = re.compile(r"([-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*|\"([]!#-[^-~ \t]|(\\[\t -~]))+\")@([-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*|\[[\t -Z^-~]*])")

def isValid(email):
    if re.fullmatch(regex, email):
        print("Valid email")
    else:
        print("Invalid email")

isValid("name.surname@gmail.com")
isValid("anonymous123@yahoo.co.uk")
isValid("anonymous123@...uk")
isValid("...@domain.us")

Результат тот же:

Valid email
Valid email
Invalid email
Invalid email

Заключение

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

Ответить