Як перевірити електронну адресу, використовуючи регулярний вираз?


3310

Протягом багатьох років я повільно розробляв регулярний вираз, який правильно перевіряє MOST-адреси електронної пошти, припускаючи, що вони не використовують IP-адресу як частину сервера.

Я використовую його в декількох програмах PHP, і він працює більшу частину часу. Однак час від часу до мене звертається хтось, хто має проблеми з сайтом, який ним користується, і мені в кінцевому підсумку потрібно внести деякі коригування (останнім часом я зрозумів, що я не дозволяю TLD з 4 символами).

Який найкращий регулярний вираз у вас є чи ви бачили для перевірки електронних листів?

Я бачив декілька рішень, які використовують функції, які використовують кілька коротших виразів, але я вважаю за краще мати один довгий складний вираз у простій функції замість кількох коротких виразів у більш складній функції.



5
Регекс, який може підтвердити правильність форматування IDNA, не вміщується в stackexchange. (правила щодо канонізації їли по-справжньому каламутну і особливо непридатні для переробки регулярних виразів)
Ясен


Режекси можуть бути змінними, оскільки в деяких випадках електронний лист може містити пробіл, а в інших випадках він не може містити жодних пробілів.
Ṃųỻịgǻňạcểơửṩ

Відповіді:


2439

Сумісне регулярний вираз повністю RFC 822 є неефективним і незрозумілим з - за його довжиною. На щастя, RFC 822 було замінено двічі, а поточна специфікація адрес електронної пошти - RFC 5322 . RFC 5322 призводить до регексу, який можна зрозуміти, якщо його вивчити протягом декількох хвилин і достатньо ефективний для фактичного використання.

Один регулярний випадок, сумісний з RFC 5322, можна знайти вгорі сторінки за адресою http://emailregex.com/, але використовує шаблон IP-адреси, який плаває по Інтернету, з помилкою, яка дозволяє 00будь-яке з непідписаних байтових знаків у десятковому значенні адреса з обмеженою крапкою, що є незаконним. З іншого боку, він здається, що він відповідає графіці RFC 5322 і проходить кілька тестів, використовуючи grep -Po, зокрема доменні імена, IP-адреси, неправильні імена імен рахунків з лапками і без них.

Виправляючи 00помилку в шаблоні IP, ми отримуємо працюючий і досить швидкий регулярний вираз. (Обчистіть відредаговану версію, а не розмітку для фактичного коду.)

(?: [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]) +) \])

або:

(?:[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])+)\])

Ось діаграма , з кінцевого автомата для регулярного виразу вище , яке є більш ясним , ніж саме регулярний вираз введіть тут опис зображення

Більш складні візерунки в Perl та PCRE (бібліотека регулярних виразів, наприклад, у PHP) може правильно аналізувати RFC 5322 без перешкод . Python та C # теж можуть це зробити, але вони використовують інший синтаксис від перших двох. Однак якщо ви змушені використовувати одну з безлічі менш потужних мов відповідності шаблонів, то краще використовувати справжній парсер.

Також важливо розуміти, що перевірка його за RFC не говорить вам абсолютно нічого про те, чи існує ця адреса насправді в наданому домені, чи людина, яка вводить адресу, є її справжнім власником. Люди таким чином постійно підписують інших людей на списки розсилки. Виправлення, що вимагає більш фантазійного типу перевірки, що передбачає надсилання на цю адресу повідомлення, яке включає маркер підтвердження, який повинен бути введений на тій же веб-сторінці, що і адреса.

Токени підтвердження - це єдиний спосіб дізнатися, що ви отримали адресу людини, яка входить. Ось чому більшість списків розсилки зараз використовують цей механізм для підтвердження реєстрації. Зрештою, будь-хто може відмовитися president@whitehouse.gov, і це навіть розбереться як законний, але це навряд чи буде особою на іншому кінці.

Для PHP, ви повинні НЕ використовувати шаблон , наведений в Validate в E-Mail з PHP, правильний шлях , з якого я цитую:

Існує певна небезпека, що загальне використання та поширене неохайне кодування встановить фактичний стандарт для адрес електронної пошти, який є більш обмежуючим, ніж записаний офіційний стандарт.

Це не краще, ніж усі інші моделі, що не належать до RFC. Це навіть не досить розумні , щоб впоратися навіть RFC 822 , НЕ кажучи вже про RFC 5322. Це одне , однак, є.

Якщо ви хочете отримати фантазію та педантичність, реалізуйте повний механізм стану . Регулярний вираз може діяти лише як фільтр рудиментарних даних. Проблема з регулярними виразами полягає в тому, що сказати комусь, що їх ідеально правильна адреса електронної пошти недійсна (помилковий позитивний), оскільки ваш регулярний вираз не може впоратися з ним просто грубо і нечесно з точки зору користувача. Державний механізм для цієї мети може як перевірити, так і навіть виправити адреси електронної пошти, які в іншому випадку вважатимуться недійсними, оскільки він розбирає адресу електронної пошти відповідно до кожного RFC. Це дозволяє отримати, можливо, приємніший досвід, наприклад

Вказана електронна адреса "myemail @ address, com" недійсна. Ви мали на увазі "myemail@address.com"?

Див. Також Валідні адреси електронної пошти , включаючи коментарі. Або порівняння електронної адреси, що підтверджує регулярні вирази .

Регулярна візуалізація виразів

Демогрійна демонстрація


179
Ви сказали: "Немає хорошого регулярного вираження". Це загальна чи специфічна для перевірки адреси електронної пошти?
Томалак

37
@Tomalak: лише для електронних адрес. Як сказав борцмейєр, RFC надзвичайно складний
Лука

37
Стаття журналу linux, яку ви згадуєте, є фактично помилковою в декількох аспектах. Зокрема, Ловелл явно не читав помилки на RFC3696 і повторює деякі помилки в опублікованій версії RFC. Більше тут: dominicsayers.com/isemail
Домінік

9
У цій публікації в блозі Джефф Етвуд є прекрасний вираз, щоб підтвердити всі дійсні адреси електронної пошти: codinghorror.com/blog/2005/02/regex-use-vs-regex-abuse.html
CMircea

5
Зауважте, що поточна специфікація HTML5 включає регулярний вираз та ABNF для перевірки введення типу електронної пошти, що навмисно більш обмежує, ніж оригінальні RFC.
Синхро

746

Не слід використовувати регулярні вирази для перевірки адрес електронної пошти.

Замість цього використовуйте клас MailAddress , як це:

try {
    address = new MailAddress(address).Address;
} catch(FormatException) {
    // address is invalid
}

MailAddressКлас використовує аналізатор BNF для перевірки адреси в повній відповідності з RFC822.

Якщо ви плануєте використовувати MailAddressдля перевірки адреси електронної пошти, пам’ятайте, що такий підхід також приймає частину відображуваного імені адреси електронної пошти, і це може бути не саме тим, що ви хочете досягти. Наприклад, він приймає ці рядки як дійсні адреси електронної пошти:

  • "user1@hotmail.com; user2@gmail.com"
  • "user1@hotmail.com; user2@gmail.com; user3@company.com"
  • "Ім’я користувача користувача user3@company.com"
  • "user4 @ company.com"

У деяких з цих випадків лише остання частина рядків розбирається як адреса; решта перед цим - ім'я відображення. Щоб отримати звичайну адресу електронної пошти без будь-якого відображуваного імені, ви можете перевірити нормалізовану адресу в порівнянні з початковою рядком.

bool isValid = false;

try
{
    MailAddress address = new MailAddress(emailAddress);
    isValid = (address.Address == emailAddress);
    // or
    // isValid = string.IsNullOrEmpty(address.DisplayName);
}
catch (FormatException)
{
    // address is invalid
}

Крім того, user@company.MailAddress також приймає адресу з крапкою в кінці .

Якщо ви дійсно хочете використовувати регулярний вираз, ось це :

(?: (?: \ r \ n)? [\ t]) * (?: (?: (?: [^ () <> @,;: \\ ". \ [\] \ 000- \ 031 ] + (?: (?: (?: \ r \ n)? [\ t]
) + | \ Z | (? = [\ ["() <> @,;: \\". \ [\]])) | "(?: [^ \" \ R \\] | \\. | (?: (?: \ r \ n)? [\ t])) * "(? :( ?:
\ r \ n)? [\ t]) *) (?: \. (?: (?: \ r \ n)? [\ t]) * (?: [^ () <> @,;: \ \ ". \ [\] \ 000- \ 031] + (? :(? :(
?: \ r \ n)? [\ t]) + | \ Z | (? = [\ ["() <> @,;: \\". \ [\]])) | "(?: [ ^ \ "\ r \\] | \\. | (?: (?: \ r \ n)? [ 
\ t])) * "(?: (?: \ r \ n)? [\ t]) *)) * @ (?: (?: \ r \ n)? [\ t]) * (?: [^ () <> @,;: \\ ". \ [\] \ 000- \ 0
31] + (?: (?: (?: \ R \ n)? [\ T]) + | \ Z | (? = [\ ["() <> @,;: \\". \ [\ ]])) | \ [([^ \ [\] \ r \\] | \\.) * \
] (?: (?: \ r \ n)? [\ t]) *) (?: \. (?: (?: \ r \ n)? [\ t]) * (?: [^ () <> @,;: \\ ". \ [\] \ 000- \ 031] +
(?: (?: (?: \ r \ n)? [\ t]) + | \ Z | (? = [\ ["() <> @,;: \\". \ [\]]) ) | \ [([^ \ [\] \ r \\] | \\.) * \] (?:
(?: \ r \ n)? [\ t]) *)) * | (?: [^ () <> @,;: \\ ". \ [\] \ 000- \ 031] + (?: (?: (?: \ r \ n)? [\ t]) + | \ Z
| (? = [\ ["() <> @,;: \\". \ [\]])) | "(?: [^ \" \ r \\] | \\. | (? :( ?: \ r \ n)? [\ t])) * "(?: (?: \ r \ n)
? [\ t]) *) * \ <(?: (?: \ r \ n)? [\ t]) * (?: @ (?: [^ () <> @,;: \\ ". \ [\] \ 000- \ 031] + (?: (?: (?: \
r \ n)? [\ t]) + | \ Z | (? = [\ ["() <> @,;: \\". \ [\]])) | \ [([^ \ [\ ] \ r \\] | \\.) * \] (?: (?: \ r \ n)? [
 \ t]) *) (?: \. (?: (?: \ r \ n)? [\ t]) * (?: [^ () <> @,;: \\ ". \ [\] \ 000- \ 031] + (?: (?: (?: \ R \ n)
? [\ t]) + | \ Z | (? = [\ ["() <> @,;: \\". \ [\]])) | \ [([^ \ [\] \ r \ \] | \\.) * \] (?: (?: \ r \ n)? [\ t]
) *)) * (?:, @ (?: (?: \ r \ n)? [\ t]) * (?: [^ () <> @,;: \\ ". \ [\] \ 000- \ 031] + (?: (?: (?: \ R \ n)? [
 \ t]) + | \ Z | (? = [\ ["() <> @,;: \\". \ [\]]) | \ [([^ \ [\] \ r \\] | \\.) * \] (?: (?: \ r \ n)? [\ t]) *
) (?: \. (?: (?: \ r \ n)? [\ t]) * (?: [^ () <> @,;: \\ ". \ [\] \ 000- \ 031 ] + (?: (?: (?: \ r \ n)? [\ t]
) + | \ Z | (? = [\ ["() <> @,;: \\". \ [\]])) | \ [([^ \ [\] \ R \\] | \\ .) * \] (?: (?: \ r \ n)? [\ t]) *)) *)
*: (?: (?: \ r \ n)? [\ t]) *)? (?: [^ () <> @,;: \\ ". \ [\] \ 000- \ 031] + (?: (?: (?: \ r \ n)? [\ t]) +
| \ Z | (? = [\ ["() <> @,;: \\". \ [\]])) | "(?: [^ \" \ R \\] | \\. | (( ?: (?: \ r \ n)? [\ t])) * "(?: (?: \ r
\ n)? [\ t]) *) (?: \. (?: (?: \ r \ n)? [\ t]) * (?: [^ () <> @,;: \\ " . \ [\] \ 000- \ 031] + (? :(? :( ?:
\ r \ n)? [\ t]) + | \ Z | (? = [\ ["() <> @,;: \\". \ [\]])) | "(?: [^ \ "\ r \\] | \\. | (?: (?: \ r \ n)? [\ t
])) * "(?: (?: \ r \ n)? [\ t]) *)) * @ (?: (?: \ r \ n)? [\ t]) * (?: [^ () <> @,;: \\ ". \ [\] \ 000- \ 031
] + (?: (?: (?: \ r \ n)? [\ t]) + | \ Z | (? = [\ ["() <> @,;: \\". \ [\] ])) | \ [([^ \ [\] \ r \\] | \\.) * \] (
?: (?: \ r \ n)? [\ t]) *) (?: \. (?: (?: \ r \ n)? [\ t]) * (?: [^ () <> @,;: \\ ". \ [\] \ 000- \ 031] + (?
: (?: (?: \ r \ n)? [\ t]) + | \ Z | (? = [\ ["() <> @,;: \\". \ [\]])) | \ [([^ \ [\] \ r \\] | \\.) * \] (? :(?
: \ r \ n)? [\ t]) *)) * \> (?: (?: \ r \ n)? [\ t]) *) | (?: [^ () <> @,; : \\ ". \ [\] \ 000- \ 031] + (? :(?
: (?: \ r \ n)? [\ t]) + | \ Z | (? = [\ ["() <> @,;: \\". \ [\]])) | "(? : [^ \ "\ r \\] | \\. | (?: (?: \ r \ n)?
[\ t])) * "(?: (?: \ r \ n)? [\ t]) *) *: (?: (?: \ r \ n)? [\ t]) * (?: (?: (?: [^ () <> @,;: \\ ". \ [\] 
\ 000- \ 031] + (?: (?: (?: \ R \ n)? [\ T]) + | \ Z | (? = [\ ["() <> @,;: \\" . \ [\]])) | "(?: [^ \" \ r \\] |
\\. | (?: (?: \ r \ n)? [\ t])) * "(?: (?: \ r \ n)? [\ t]) *) (?: \. (? : (?: \ r \ n)? [\ t]) * (?: [^ () <>

@,;: \\ ". \ [\] \ 000- \ 031] + (?: (?: (?: \ R \ n)? [\ T]) + | \ Z | (? = [\ [ "() <> @,;: \\". \ [\]])) "
(?: [^ \ "\ r \\] | \\. | (?: (?: \ r \ n)? [\ t])) *" (?: (?: \ r \ n)? [ \ t]) *)) * @ (?: (?: \ r \ n)? [\ t]
) * (?: [^ () <> @,;: \\ ". \ [\] \ 000- \ 031] + (?: (?: (?: \ R \ n)? [\ T]) + | \ Z | (? = [\ ["() <> @,;: \\
". \ [\]])) | \ [([^ \ [\] \ r \\] | \\.) * \] (?: (?: \ r \ n)? [\ t]) * ) (?: \. (?: (?: \ r \ n)? [\ t]) * (?
: [^ () <> @,;: \\ ". \ [\] \ 000- \ 031] + (?: (?: (?: \ R \ n)? [\ T]) + | \ Z | (? = [\ ["() <> @,;: \\". \ [
\]])) | \ [([^ \ [\] \ r \\] | \\.) * \] (?: (?: \ r \ n)? [\ t]) *)) * | (?: [^ () <> @,;: \\ ". \ [\] \ 000-
\ 031] + (?: (?: (?: \ R \ n)? [\ T]) + | \ Z | (? = [\ ["() <> @,;: \\". \ [ \]])) | "(?: [^ \" \ r \\] | \\. | ((
?: (?: \ r \ n)? [\ t])) * "(?: (?: \ r \ n)? [\ t]) *) * \ <(?: (?: \ r \ n)? [\ t]) * (?: @ (?: [^ () <> @,;
: \\ ". \ [\] \ 000- \ 031] + (?: (?: (?: \ R \ n)? [\ T]) + | \ Z | (? = [\ [" () <> @,;: \\ ". \ [\]])) | \ [([
^ \ [\] \ r \\] | \\.) * \] (?: (?: \ r \ n)? [\ t]) *) (?: \. (?: (?: \ r \ n)? [\ t]) * (?: [^ () <> @,;: \\ "
. \ [\] \ 000- \ 031] + (?: (?: (?: \ R \ n)? [\ T]) + | \ Z | (? = [\ ["() <> @, ;: \\ ". \ [\]])) | \ [([^ \ [\
] \ r \\] | \\.) * \] (?: (?: \ r \ n)? [\ t]) *)) * (?:, @ (?: (?: \ r \ n )? [\ t]) * (?: [^ () <> @,;: \\ ". \
[\] \ 000- \ 031] + (?: (?: (?: \ R \ n)? [\ T]) + | \ Z | (? = [\ ["() <> @,;: \\ ". \ [\]])) | \ [([^ \ [\] \
r \\] | \\.) * \] (?: (?: \ r \ n)? [\ t]) *) (?: \. (?: (?: \ r \ n)? [\ t]) * (?: [^ () <> @,;: \\ ". \ [\] 
\ 000- \ 031] + (?: (?: (?: \ R \ n)? [\ T]) + | \ Z | (? = [\ ["() <> @,;: \\" . \ [\]])) | \ [([^ \ [\] \ r \\]
| \\.) * \] (?: (?: \ r \ n)? [\ t]) *)) *) *: (?: (?: \ r \ n)? [\ t]) * )? (?: [^ () <> @,;: \\ ". \ [\] \ 0
00- \ 031] + (?: (?: (?: \ R \ n)? [\ T]) + | \ Z | (? = [\ ["() <> @,;: \\". \ [\]])) | "(?: [^ \" \ r \\] | \\
. | (?: (?: \ r \ n)? [\ t])) * "(?: (?: \ r \ n)? [\ t]) *) (?: \. (? :( ?: \ r \ n)? [\ t]) * (?: [^ () <> @,
;: \\ ". \ [\] \ 000- \ 031] + (?: (?: (?: \ R \ n)? [\ T]) + | \ Z | (? = [\ [" ( ) <> @,;: \\ ". \ [\]])) |" (?
: [^ \ "\ r \\] | \\. | (?: (?: \ r \ n)? [\ t])) *" (?: (?: \ r \ n)? [\ t ]) *)) * @ (?: (?: \ r \ n)? [\ t]) *
(?: [^ () <> @,;: \\ ". \ [\] \ 000- \ 031] + (?: (?: (?: \ R \ n)? [\ T]) + | \ Z | (? = [\ ["() <> @,;: \\".
\ [\]])) | \ [([^ \ [\] \ r \\] | \\.) * \] (?: (?: \ r \ n)? [\ t]) *) ( ?: \. (?: (?: \ r \ n)? [\ t]) * (?: [
^ () <> @,;: \\ ". \ [\] \ 000- \ 031] + (?: (?: (?: \ R \ n)? [\ T]) + | \ Z | ( ? = [\ ["() <> @,;: \\". \ [\]
])) | \ [([^ \ [\] \ r \\] | \\.) * \] (?: (?: \ r \ n)? [\ t]) *)) * \> ( ?: (?: \ r \ n)? [\ t]) *) (?:, \ s * (
?: (?: [^ () <> @,;: \\ ". \ [\] \ 000- \ 031] + (?: (?: (?: \ R \ n)? [\ T]) + | \ Z | (? = [\ ["() <> @,;: \\
". \ [\]])) |" (?: [^ \ "\ r \\] | \\. | (?: (?: \ r \ n)? [\ t])) *" (? : (?: \ r \ n)? [\ t]) *) (?: \. (? :(
?: \ r \ n)? [\ t]) * (?: [^ () <> @,;: \\ ". \ [\] \ 000- \ 031] + (? :(? :(? : \ r \ n)? [\ t]) + | \ Z | (? = [
\ ["() <> @,;: \\". \ [\]])) | "(?: [^ \" \ r \\] | \\. | (?: (?: \ r \ n)? [\ t])) * "(?: (?: \ r \ n)? [\ t
]) *)) * @ (?: (?: \ r \ n)? [\ t]) * (?: [^ () <> @,:: \\ ". \ [\] \ 000- \ 031] + (?: (?: (?: \ R \ n)? [\ T
]) + | \ Z | (? = [\ ["() <> @,;: \\". \ [\]]) | \ [([^ \ [\] \ R \\] | \ \.) * \] (?: (?: \ r \ n)? [\ t]) *) (?
: \. (?: (?: \ r \ n)? [\ t]) * (?: [^ () <> @,;: \\ ". \ [\] \ 000- \ 031] + ( ?: (?: (?: \ r \ n)? [\ t]) + |
\ Z | (? = [\ ["() <> @,;: \\". \ [\]])) | \ [([^ \ [\] \ R \\] | \\.) * \] (?: (?: \ r \ n)? [\ t]) *)) * | (?:
[^ () <> @,;: \\ ". \ [\] \ 000- \ 031] + (?: (?: (?: \ R \ n)? [\ T]) + | \ Z | (? = [\ ["() <> @,;: \\". \ [\
]])) | "(?: [^ \" \ r \\] | \\. | (?: (?: \ r \ n)? [\ t])) * "(?: (?: (?: \ r \ n)? [\ t]) *) * \ <(?: (?: \ r \ n)
? [\ t]) * (?: @ (?: [^ () <> @,;: \\ ". \ [\] \ 000- \ 031] + (?: (?: (?: \ r \ n)? [\ t]) + | \ Z | (? = [\ ["
() <> @,;: \\ ". \ [\]]) | \ [([^ \ [\] \ r \\] | \\.) * \] (?: (?: \ r \ n)? [\ t]) *) (?: \. (?: (?: \ r \ n)
? [\ t]) * (?: [^ () <> @,;: \\ ". \ [\] \ 000- \ 031] + (?: (?: (?: \ r \ n)? [\ t]) + | \ Z | (? = [\ ["() <>

@,;: \\ ". \ [\]])) | \ [([^ \ [\] \ r \\] | \\.) * \] (?: (?: \ r \ n)? [\ t]) *)) * (?:, @ (?: (?: \ r \ n)? [
 \ t]) * (?: [^ () <> @,;: \\ ". \ [\] \ 000- \ 031] + (?: (?: (?: \ r \ n)? [\ t]) + | \ Z | (? = [\ ["() <> @,
;: \\ ". \ [\]])) | \ [([^ \ [\] \ r \\] | \\.) * \] (?: (?: \ r \ n)? [\ t]) *) (?: \. (?: (?: \ r \ n)? [\ t]
) * (?: [^ () <> @,;: \\ ". \ [\] \ 000- \ 031] + (?: (?: (?: \ R \ n)? [\ T]) + | \ Z | (? = [\ ["() <> @,;: \\
". \ [\]])) | \ [([^ \ [\] \ r \\] | \\.) * \] (?: (?: \ r \ n)? [\ t]) * )) *) *: (?: (?: \ r \ n)? [\ t]) *)?
(?: [^ () <> @,;: \\ ". \ [\] \ 000- \ 031] + (?: (?: (?: \ R \ n)? [\ T]) + | \ Z | (? = [\ ["() <> @,;: \\".
\ [\]])) | "(?: [^ \" \ r \\] | \\. | (?: (?: \ r \ n)? [\ t])) * "(? :( ?: \ r \ n)? [\ t]) *) (?: \. (? :( ?:
\ r \ n)? [\ t]) * (?: [^ () <> @,;: \\ ". \ [\] \ 000- \ 031] + (?: (?: (?: \ r \ n)? [\ t]) + | \ Z | (? = [\ [
"() <> @,;: \\". \ [\]])) | "(?: [^ \" \ r \\] | \\. | (?: (?: \ r \ n) ? [\ t])) * "(?: (?: \ r \ n)? [\ t])
*)) * @ (?: (?: \ r \ n)? [\ t]) * (?: [^ () <> @,:: \\ ". \ [\] \ 000- \ 031] + (?: (?: (?: \ r \ n)? [\ t])
+ | \ Z | (? = [\ ["() <> @,;: \\". \ [\]])) | \ [([^ \ [\] \ R \\] | \\. ) * \] (?: (?: \ r \ n)? [\ t]) *) (?: \
. (?: (?: \ r \ n)? [\ t]) * (?: [^ () <> @,;: \\ ". \ [\] \ 000- \ 031] + (?: (?: (?: \ r \ n)? [\ t]) + | \ Z
| (? = [\ ["() <> @,;: \\". \ [\]])) | \ [([^ \ [\] \ r \\] | \\.) * \] (?: (?: \ r \ n)? [\ t]) *)) * \> (? :(
?: \ r \ n)? [\ t]) *)) *)?; \ s *)

26
Ви побачите, що клас MailAddress в .NET 4.0 набагато кращий для перевірки електронних адрес, ніж у попередніх версіях. Я вніс кілька суттєвих удосконалень.
Джефф Такер

7
Я думаю, що це ... не працює ... для більш простих ідентифікаторів. a @ b не підтверджує. ar@b.com відповідає лише до ar @ b, .com не відповідає. Однак щось на кшталт "Я я" @ [10.10.10.10] справді працює! :)
Raze

5
Будьте попереджені, що ці валідатори, сумісні з RFC, перевіряють багато електронних адрес, які ви, ймовірно, не хотіли б прийняти, наприклад, "a <body / onload = alert (' lol.com?'+document.cookies ) @aa> ", що є дійсною адресою електронної пошти в електронному листі Perl: Дійсно (що використовує цей величезний регулярний вираз), і його можна використовувати для XSS rt.cpan.org/Public/Bug/Display.html?id=75650
Matthew Lock,

9
@MatthewLock: Це не гірше fake@not-a-real-domain.name. Ви не повинні покладатися на перевірку електронної пошти, щоб запобігти XSS.
SLaks

10
@MatthewLock: Ні. Вам потрібно уникати SQL запитів (а ще краще, використовувати параметри). Санітарія - це не належний захист.
СЛАкс

536

Це питання задають багато, але я думаю, ви повинні відступити і запитати себе, чому ви хочете синтаксично підтвердити адреси електронної пошти? Яка користь насправді?

  • Це не спіймає звичайних помилок.
  • Це не заважає людям вводити недійсні або складені електронні адреси або вводити чужу адресу.

Якщо ви хочете перевірити правильність електронного листа, у вас немає іншого вибору, ніж надіслати підтвердження електронною поштою та дати відповідь на це. У багатьох випадках вам доведеться відправити підтвердження електронною поштою з міркувань безпеки або з етичних міркувань (тому ви не можете, наприклад, підписати когось на службу проти їхньої волі).


92
Можливо, варто перевірити, що вони ввели щось @ щось у поле для перевірки на стороні клієнта лише для того, щоб зафіксувати прості помилки - але в цілому ви праві.
Мартін Бекетт

8
Мартіне, я дав тобі +1, щоб пізніше прочитати, що foobar @ dk - це дійсний електронний лист. Це було б не дуже, але якщо ви хочете бути сумісними з RFC І використовувати здоровий глузд, вам слід виявити такі випадки, як і попросити користувача підтвердити, що це правильно.
philfreo

105
@olavk: якщо хтось вводить помилку (наприклад:) me@hotmail, він, очевидно, не отримає ваш електронний лист із підтвердженням, і де вони? Вони більше не є на вашому сайті, і їм цікаво, чому вони не змогли зареєструватися. Насправді ні, вони не є - вони зовсім забули про тебе. Однак, якщо ви могли просто провести основну перевірку правильності за допомогою регексу, поки вони все ще з вами, вони можуть відразу зрозуміти цю помилку, і ви отримаєте щасливого користувача.
nickf

5
@JacquesB: Ви чудово зазначаєте. Тільки тому, що він проходить збирання на RFC, це не означає, що це дійсно адреса користувача. В іншому випадку всі ці president@whitehouse.govадреси вказують на дуже запеклого головнокомандувача. :)
tchrist

39
Він не повинен бути чорним чи білим. Якщо електронна пошта виглядає неправильно, повідомте про це користувачеві. Якщо користувач все ж хоче продовжити, дозвольте йому. Не змушуйте користувача відповідати вашому регексу, скоріше, використовуйте регулярний вираз як інструмент, щоб допомогти користувачеві знати, що може статися помилка.
ninjaneer

354

Все залежить від того, наскільки точним ви хочете бути. Для моїх цілей, де я просто намагаюся не захищати такі речі bob @ aol.com(пробіли в електронних листах) або steve(взагалі немає домену) або mary@aolcom(немає періоду до .com)

/^\S+@\S+\.\S+$/

Звичайно, він відповідатиме речам, які не є дійсними адресами електронної пошти, але справа в тому, щоб отримати звичайні прості помилки.

Існує будь-яка кількість змін, які можуть бути внесені до цього регулярного виразу (а деякі є в коментарях до цієї відповіді), але це просто і легко зрозуміти, і це перша перша спроба.


6
Це не відповідає foobar @ dk, що є дійсною та робочою адресою електронної пошти (хоча, ймовірно, більшість поштових серверів не прийме її або додасть
щось.com

3
Так, буде. Я пропоную спробувати самі. $ perl -le'print q{foo@bar.co.uk} = ~ /^\S+@\S+\.\S+$/? q {Y}: q {N} '
Енді Лестер

7
@Richard: .включений у \S.
Девід Торнлі

43
JJJ: Так, це буде відповідати великій дурі. Це буде відповідати & $ * # $ (@ $ 0 (%)) $ #.) & *) (* $, Теж. Для мене, я більше стосується лову непарної нишпорити пальці помилки , як , mary@aolcomчим я повний сміття YMMV.
Енді Лестер

5
Просто для контролю @знаків: /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/ jsfiddle.net/b9chris/mXB96
Кріс

338

Це залежить від того, що ви маєте на увазі найкраще: Якщо ви говорите про ловлю кожної дійсної адреси електронної пошти, використовуйте наступне:

(?:(?:\r\n)?[ \t])*(?:(?:(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t]
)+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:
\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(
?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ 
\t]))*"(?:(?:\r\n)?[ \t])*))*@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\0
31]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\
](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+
(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:
(?:\r\n)?[ \t])*))*|(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z
|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)
?[ \t])*)*\<(?:(?:\r\n)?[ \t])*(?:@(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\
r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[
 \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)
?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t]
)*))*(?:,@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[
 \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*
)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t]
)+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*)
*:(?:(?:\r\n)?[ \t])*)?(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+
|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r
\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:
\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t
]))*"(?:(?:\r\n)?[ \t])*))*@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031
]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](
?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?
:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?
:\r\n)?[ \t])*))*\>(?:(?:\r\n)?[ \t])*)|(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?
:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?
[ \t]))*"(?:(?:\r\n)?[ \t])*)*:(?:(?:\r\n)?[ \t])*(?:(?:(?:[^()<>@,;:\\".\[\] 
\000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|
\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>
@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"
(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*))*@(?:(?:\r\n)?[ \t]
)*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\
".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?
:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[
\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*|(?:[^()<>@,;:\\".\[\] \000-
\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(
?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)*\<(?:(?:\r\n)?[ \t])*(?:@(?:[^()<>@,;
:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([
^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\"
.\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\
]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*(?:,@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\
[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\
r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] 
\000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]
|\\.)*\](?:(?:\r\n)?[ \t])*))*)*:(?:(?:\r\n)?[ \t])*)?(?:[^()<>@,;:\\".\[\] \0
00-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\
.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,
;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?
:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*))*@(?:(?:\r\n)?[ \t])*
(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".
\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[
^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]
]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*\>(?:(?:\r\n)?[ \t])*)(?:,\s*(
?:(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\
".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)(?:\.(?:(
?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[
\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t
])*))*@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t
])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?
:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|
\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*|(?:
[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\
]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)*\<(?:(?:\r\n)
?[ \t])*(?:@(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["
()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)
?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>
@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*(?:,@(?:(?:\r\n)?[
 \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,
;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t]
)*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\
".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*)*:(?:(?:\r\n)?[ \t])*)?
(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".
\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)(?:\.(?:(?:
\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\[
"()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])
*))*@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])
+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\
.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z
|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*\>(?:(
?:\r\n)?[ \t])*))*)?;\s*)

( http://www.ex-parrot.com/~pdw/Mail-RFC822-Address.html ) Якщо ви шукаєте щось простіше, але це дозволить отримати більшість дійсних адрес електронної пошти, спробуйте щось на кшталт:

"^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$"

EDIT: За посиланням:

Цей регулярний вираз буде лише підтверджувати адреси, на яких будь-які коментарі позбавлені та замінені пробілом (це робиться модулем).


10
Він не відповідає всім адресам, деякі повинні бути перетворені спочатку. За посиланням: "Цей регулярний вираз підтверджує лише адреси, у яких були зачислені будь-які коментарі та замінені пробілом (це робиться модулем)."
Час. Овенс

47
Чи можете ви надати мені приклад того, email addressщо неправильно проходить через другий, але його спіймає довший вираз?
Лазер

4
Хоча я колись любив це, це валідатор RFC 822, а не RFC 5322 .
tchrist

24
@Lazer in..valid @ example.com буде простим прикладом. Вам не дозволяється мати дві послідовні без котировки точки в локальній частині.
Рандаль Шварц

5
@Mikhail perl, але насправді не варто ним користуватися.
Хороша людина

287

[ОНОВЛЕНО] Я зіставив тут усе, що я знаю про перевірку адрес електронної пошти: http://isemail.info , який зараз не тільки підтверджує, але й діагностує проблеми з адресами електронної пошти. Я погоджуюся з багатьма коментарями тут, що перевірка є лише частиною відповіді; дивіться моє есе на веб- сайті http://isemail.info/about .

Наскільки я знаю, is_email () залишається єдиним валідатором, який остаточно скаже вам, чи вказана рядок є дійсною адресою електронної пошти чи ні. Я завантажив нову версію на http://isemail.info/

Я зіставив тестові випадки від Cal Henderson, Dave Child, Phil Haack, Doug Lovell, RFC5322 та RFC 3696. 275 тестових адрес. Я провів усі ці тести на всіх вільних валідаторах, які я міг знайти.

Я спробую оновлювати цю сторінку, оскільки люди покращують свої валідатори. Дякую Калу, Майклу, Дейву, Полу та Філу за допомогу та співпрацю у складанні цих тестів та конструктивній критиці мого власного валідатора .

Люди повинні знати про помилки, зокрема, щодо RFC 3696 . Три з канонічних прикладів насправді є недійсними адресами. І максимальна довжина адреси - 254 або 256 символів, а не 320.


Цей валідатор також здається правильним. [... час минає ...] Гм, схоже, це просто RFC 5322, а не 3693 або помилка.
tchrist

1
Дуже хороший. Тут ми не лише отримуємо приємний твір, ми отримуємо тестер перевірки, а також бібліотеку для завантаження. Гарна відповідь!
bgmCoder

Ваш валідатор не підтримує Punycode (RFC 3492). name@öäü.at може бути дійсною адресою. (це перекладається на name@xn--4ca9at.at)
Йозеф каже: Відновити Моніку

Привіт @Josef. Спробуйте перевірити, name@xn--4ca9at.atоскільки цей код стосується перевірки, а не тлумачення. Якщо ви хочете додати перекладача з пунктоди,
Домінік Сайерс

266

За специфікацією W3C HTML5 :

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

Контекст:

Дійсний адреса електронної пошти є рядком , яка відповідає виробництву ABNF [...].

Примітка: Ця вимога є навмисним порушенням в RFC 5322 , який визначає синтаксис для адрес електронної пошти , які одночасно занадто строго (до символу «@»), занадто розпливчасто (після символу «@»), і занадто слабке ( дозволяючи коментарям, символам пробілу та цитованим рядкам у незнайомих для більшості користувачів манерах) бути корисними тут.

Наступне регулярне вираження, сумісне з JavaScript і Perl, є реалізацією вищезазначеного визначення.

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


12
Це цікаво. Це порушення RFC, але навмисне, і це робить sesne. Приклад із реального світу: gmail ігнорує точки в частині перед @, тому якщо ваш електронний лист test@gmail.com, ви можете надсилати електронні листи для тестування. @ Gmail.com або test .... @ gmail.com, обидві ці адреси є недійсний згідно з RFC, але дійсний у реальному світі.
valentinas

Я думаю, що остання частина повинна бути "+" замість "*": ^ [a-zA-Z0-9. # $% & '* + / =? ^ _ `{|} ~ -] + @ [a- zA-Z0-9 -] + (?: \. [a-zA-Z0-9 -] +) + $
ммммм

7
@mmmmmm john.doe@localhostє дійсним. Звичайно, в реальному додатку (тобто спільноті) я хотів би запропонувати вам замінити * на +
rabudde

3
@valentinas Насправді, RFC не виключає цих локальних частин, але їх треба цитувати. "test...."@gmail.comє абсолютно дійсним відповідно до RFC і семантично еквівалентний test....@gmail.com.
Рінке

Я отримую помилку під час спроби надіслати електронну пошту за допомогою python через реле моєї компанії, якщо я спробую надіслати адресу за адресою. @ Або .. @. Насправді це теж випадок з _ @. Я швидше видаляю їх перед відправкою, ніж довіряю, що одержувач це зробить.
ndvo

201

Це просто в Perl 5.10 або новіших версіях:

/(?(DEFINE)
   (?<address>         (?&mailbox) | (?&group))
   (?<mailbox>         (?&name_addr) | (?&addr_spec))
   (?<name_addr>       (?&display_name)? (?&angle_addr))
   (?<angle_addr>      (?&CFWS)? < (?&addr_spec) > (?&CFWS)?)
   (?<group>           (?&display_name) : (?:(?&mailbox_list) | (?&CFWS))? ;
                                          (?&CFWS)?)
   (?<display_name>    (?&phrase))
   (?<mailbox_list>    (?&mailbox) (?: , (?&mailbox))*)

   (?<addr_spec>       (?&local_part) \@ (?&domain))
   (?<local_part>      (?&dot_atom) | (?&quoted_string))
   (?<domain>          (?&dot_atom) | (?&domain_literal))
   (?<domain_literal>  (?&CFWS)? \[ (?: (?&FWS)? (?&dcontent))* (?&FWS)?
                                 \] (?&CFWS)?)
   (?<dcontent>        (?&dtext) | (?&quoted_pair))
   (?<dtext>           (?&NO_WS_CTL) | [\x21-\x5a\x5e-\x7e])

   (?<atext>           (?&ALPHA) | (?&DIGIT) | [!#\$%&'*+-/=?^_`{|}~])
   (?<atom>            (?&CFWS)? (?&atext)+ (?&CFWS)?)
   (?<dot_atom>        (?&CFWS)? (?&dot_atom_text) (?&CFWS)?)
   (?<dot_atom_text>   (?&atext)+ (?: \. (?&atext)+)*)

   (?<text>            [\x01-\x09\x0b\x0c\x0e-\x7f])
   (?<quoted_pair>     \\ (?&text))

   (?<qtext>           (?&NO_WS_CTL) | [\x21\x23-\x5b\x5d-\x7e])
   (?<qcontent>        (?&qtext) | (?&quoted_pair))
   (?<quoted_string>   (?&CFWS)? (?&DQUOTE) (?:(?&FWS)? (?&qcontent))*
                        (?&FWS)? (?&DQUOTE) (?&CFWS)?)

   (?<word>            (?&atom) | (?&quoted_string))
   (?<phrase>          (?&word)+)

   # Folding white space
   (?<FWS>             (?: (?&WSP)* (?&CRLF))? (?&WSP)+)
   (?<ctext>           (?&NO_WS_CTL) | [\x21-\x27\x2a-\x5b\x5d-\x7e])
   (?<ccontent>        (?&ctext) | (?&quoted_pair) | (?&comment))
   (?<comment>         \( (?: (?&FWS)? (?&ccontent))* (?&FWS)? \) )
   (?<CFWS>            (?: (?&FWS)? (?&comment))*
                       (?: (?:(?&FWS)? (?&comment)) | (?&FWS)))

   # No whitespace control
   (?<NO_WS_CTL>       [\x01-\x08\x0b\x0c\x0e-\x1f\x7f])

   (?<ALPHA>           [A-Za-z])
   (?<DIGIT>           [0-9])
   (?<CRLF>            \x0d \x0a)
   (?<DQUOTE>          ")
   (?<WSP>             [\x20\x09])
 )

 (?&address)/x

20
Я хотів би побачити це в Python
tdc

4
Я вважаю, що лише підмножина addrspecчастини справді має відношення до питання. Прийняти більше цього та переслати його, хоча якась інша частина системи, яка не готова прийняти повні RFC5822 адреси, схожа на зйомку - це ваша власна нога.
долмен

3
Чудово (+1), але в технічному плані це звичайно не підсумок ... (що було б неможливо, оскільки граматика не є регулярною).
Рінке

10
регулярні виразки перестали бути регулярними. Це дійсний «регулярний вираз» Perl!
rjh

4
Я налаштував тест на цей регулярний вираз на IDEone: ideone.com/2XFecH Однак він не спрацьовує "ідеально". Хтось би не піклувався? Я щось пропускаю?
Майк

159

я використовую

^\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$

Який використовується в ASP.NET регулятором RegularExpressionValidator.


28
Бу! Мою (необдуману) адресу !@mydomain.netвідхилено.
Фрогз

3
Відповідно до цієї сторінки data.iana.org/TLD/tlds-alpha-by-domain.txt немає доменів із лише одним символом на верхньому рівні, наприклад "something.c", "something.a", ось версія, що підтримка принаймні 2 символів: "something.pl", "something.us":^\\w+([-+.']\\w+)*@\\w+([-.]\\w+)*\\.\\w{2,}([-.]\\w+)*$
Tomasz Szulc

4
@Wayne Whitty. Ви торкнулися першочергового питання, чи потрібно обслуговувати переважну більшість адрес, або ВСІ, включаючи ті, які ніхто не використовував, окрім тестування перевірки електронної пошти.
Патанджалі

@TomaszSzulc додаткова косою рисою у вашій відповіді є заплутаною, я просто виправив її, і працює 2 символів доменних імен, працює ^ ^ w + ([- +. '] \ W +) * @ \ w + ([-.] \ W +) * \. \ w {2,} ([-.] \ w +) * $
Aqib Mumtaz

2
ця помилка, на simon-@hotmail.comякій насправді діє (у нашого клієнта була аналогічна адреса) `
Simon_Weaver

142

Не знаю найкращого, але цей принаймні правильний, доки в адресах знімаються коментарі та замінюються пробіли.

Серйозно. Ви повинні використовувати вже написану бібліотеку для перевірки електронних листів. Найкращий спосіб - це, мабуть, просто надіслати підтвердження електронною поштою на цю адресу.


2
Наскільки я знаю, деякі бібліотеки теж помиляються. Я смутно пам'ятаю, що PHP PEAR був такий помилок.
борцмейєр

На цій сторінці внизу є відмова від відповідальності про пару речей із специфікації. що regexp не підтримує.
Кріс Вест

7
Це специфікація RFC 822, а не специфікація RFC 5322 .
tchrist

12
Зрештою, він правий у тому, що єдиний спосіб справді підтвердити електронну адресу - це надіслати електронний лист на нього та чекати відповіді.
Blazemonger

109

Адреси електронної пошти, які я хочу перевірити, буде використовуватися веб-програмою ASP.NET за допомогою простору імен System.Net.Mail для надсилання електронних листів до списку людей. Отже, замість того, щоб використовувати дуже складний регулярний вираз, я просто намагаюся створити екземпляр MailAddress з адреси. Конструктор MailAddress видасть виняток, якщо адреса неправильно сформована. Таким чином, я знаю, що я можу принаймні отримати електронний лист із дверей. Звичайно, це перевірка на стороні сервера, але як мінімум вам це потрібно.

protected void emailValidator_ServerValidate(object source, ServerValidateEventArgs args)
{
    try
    {
        var a = new MailAddress(txtEmail.Text);
    }
    catch (Exception ex)
    {
        args.IsValid = false;
        emailValidator.ErrorMessage = "email: " + ex.Message;
    }
}

3
Хороший момент. Навіть якщо ця перевірка сервера відхиляє деяку дійсну адресу, це не є проблемою, оскільки ви не зможете надіслати цю адресу за допомогою цієї конкретної серверної технології. Або ви можете спробувати робити те саме, використовуючи будь-яку бібліотеку електронної пошти третьої сторони, яку ви використовуєте замість інструментів за замовчуванням.
Користувач

Мені дуже подобається, як це використовує .Net рамковий код - немає сенсу винаходити колесо. Це чудово. Простий, чистий та гарантує, що ви можете фактично надсилати електронний лист. Чудова робота.
Cory House

... так, і для тих, хто цікавиться, як він перевіряє, дивляться на код у Reflector - його є зовсім небагато - і це не регулярний вираз!
Том Картер

2
Лише зауваження: клас MailAddress не відповідає RFC5322, якщо ви просто хочете використовувати його для перевірки (а також не надсилати, і в цьому випадку це питання суперечки, як згадувалося вище). Див: stackoverflow.com/questions/6023589 / ...
Поргеса

Лише незначна проблема: якщо ви хочете зробити код валідатора на вашій стороні сервера більш багаторазовим (або в цьому випадку, або взагалі), я пропоную використовувати args.Valueзамість посилання на поле як txtEmail.Textжорстке кодування. Останній прив’яже ваш валідатор до єдиного екземпляра управління, це може бути добре, якщо у вас є одне поле електронної пошти, але не рекомендується інакше.
pholpar

109

Швидка відповідь

Використовуйте такий регекс для перевірки введення:

([-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*|"([]!#-[^-~ \t]|(\\[\t -~]))+")@[0-9A-Za-z]([0-9A-Za-z-]{0,61}[0-9A-Za-z])?(\.[0-9A-Za-z]([0-9A-Za-z-]{0,61}[0-9A-Za-z])?)+

Адреси, відповідні цьому регексу:

  • мати локальну частину (тобто частину до @ -сигналу), яка суворо відповідає RFC 5321/5322,
  • мають доменну частину (тобто частину після @ -сигналу), що є ім'ям хоста, що має принаймні дві мітки, кожна з яких має максимум 63 символи.

Другим обмеженням є обмеження на RFC 5321/5322.

Детальна відповідь

Використання регулярного виразу, який розпізнає адреси електронної пошти, може бути корисним у різних ситуаціях: наприклад, для сканування адрес електронної пошти в документі, для перевірки введення користувача або як обмеження цілісності у сховищі даних.

Однак слід зазначити, що якщо ви хочете дізнатися, чи адреса насправді посилається на існуючу поштову скриньку, заміни для надсилання повідомлення на адресу не існує. Якщо ви хочете лише перевірити, чи адресна граматично правильна, ви можете використовувати регулярний вираз, але зауважте, що ""@[]це граматично правильна адреса електронної пошти, яка, безумовно, не стосується існуючої поштової скриньки.

Синтаксис адрес електронної пошти визначений у різних RFC , особливо серед RFC 822 та RFC 5322 . RFC 822 слід розглядати як "оригінальний" стандарт, а RFC 5322 - як останній стандарт. Синтаксис, визначений в RFC 822, є найбільш м'яким, і наступні стандарти обмежували синтаксис все далі і далі, коли новіші системи або служби повинні розпізнавати застарілий синтаксис, але ніколи не створювати його.

У цій відповіді я візьму "адресу електронної пошти" на значення addr-spec, визначене в RFC (тобто jdoe@example.org, але ні "John Doe"<jdoe@example.org>, ні some-group:jdoe@example.org,mrx@exampel.org;).

Є одна проблема з перекладом синтаксисів RFC в регулярні вирази: синтаксиси не є регулярними! Це пояснюється тим, що вони дозволяють отримати необов'язкові коментарі в адресах електронної пошти, які можна нескінченно вкладати, тоді як нескінченне вкладення не може бути описане регулярним виразом. Для сканування або підтвердження адрес, що містять коментарі, вам потрібно проаналізувати чи більш потужні вирази. (Зверніть увагу, що такі мови, як Perl, мають конструкції для опису контекстних граматик, що нагадують регулярні виразки.) У цій відповіді я нехту коментарями та розглядаю лише правильні регулярні вирази.

RFC визначають синтаксиси для повідомлень електронної пошти, а не для адрес електронної пошти як таких. Адреси можуть з’являтися в різних полях заголовків, і саме там вони визначаються в першу чергу. Коли вони з’являються у полях заголовків, адреси можуть містити (між лексичними лексемами) пробіли, коментарі та навіть рядкові рядки. Однак семантично це значення не має. Видаляючи цей пробіл тощо з адреси, ви отримуєте семантично еквівалентне канонічне зображення . Таким чином, канонічне зображення first. last (comment) @ [3.5.7.9]є first.last@[3.5.7.9].

Для різних цілей слід використовувати різні синтаксиси. Якщо ви хочете сканувати адреси електронної пошти в (можливо, дуже старому) документі, може бути корисною використовувати синтаксис, визначений в RFC 822. З іншого боку, якщо ви хочете перевірити введення користувача, ви можете скористатися синтаксис, визначений у RFC 5322, ймовірно, приймає лише канонічні уявлення. Ви повинні вирішити, який синтаксис застосовується до конкретного випадку.

Я використовую POSIX "розширені" регулярні вирази в цій відповіді, припускаючи ASCII сумісний набір символів.

RFC 822

Я прийшов до наступного регулярного виразу. Запрошую всіх спробувати розбити. Якщо ви знайдете помилкові позитиви чи помилкові негативи, будь ласка, опублікуйте їх у коментарі, і я спробую виправити вираз якомога швидше.

([^][()<>@,;:\\". \x00-\x1F\x7F]+|"(\n|(\\\r)*([^"\\\r\n]|\\[^\r]))*(\\\r)*")(\.([^][()<>@,;:\\". \x00-\x1F\x7F]+|"(\n|(\\\r)*([^"\\\r\n]|\\[^\r]))*(\\\r)*"))*@([^][()<>@,;:\\". \x00-\x1F\x7F]+|\[(\n|(\\\r)*([^][\\\r\n]|\\[^\r]))*(\\\r)*])(\.([^][()<>@,;:\\". \x00-\x1F\x7F]+|\[(\n|(\\\r)*([^][\\\r\n]|\\[^\r]))*(\\\r)*]))*

Я вважаю, що він повністю відповідає RFC 822, включаючи errata . Він розпізнає лише адреси електронної пошти у їхній канонічній формі. Зворотний вираз, який розпізнає (складений) пробіл, див. Виведення нижче.

Виведення показує, як я дійшов до виразу. Я перераховую всі відповідні граматичні правила з RFC саме так, як вони з'являються, а потім відповідне регулярне вираження. Там, де помилка опублікована, я даю окремий вираз для виправленого правила граматики (з позначкою "помилка") і використовую оновлену версію як підвираз у наступних регулярних виразах.

Як зазначено в пункті 3.1.4. RFC 822 необов'язковий лінійний пробіл білого кольору може бути вставлений між лексичними лексемами. Де можливо, я розширив вирази, щоб відповідати цьому правилу, і позначив результат "opt-lwsp".

CHAR        =  <any ASCII character>
            =~ .

CTL         =  <any ASCII control character and DEL>
            =~ [\x00-\x1F\x7F]

CR          =  <ASCII CR, carriage return>
            =~ \r

LF          =  <ASCII LF, linefeed>
            =~ \n

SPACE       =  <ASCII SP, space>
            =~  

HTAB        =  <ASCII HT, horizontal-tab>
            =~ \t

<">         =  <ASCII quote mark>
            =~ "

CRLF        =  CR LF
            =~ \r\n

LWSP-char   =  SPACE / HTAB
            =~ [ \t]

linear-white-space =  1*([CRLF] LWSP-char)
                   =~ ((\r\n)?[ \t])+

specials    =  "(" / ")" / "<" / ">" / "@" /  "," / ";" / ":" / "\" / <"> /  "." / "[" / "]"
            =~ [][()<>@,;:\\".]

quoted-pair =  "\" CHAR
            =~ \\.

qtext       =  <any CHAR excepting <">, "\" & CR, and including linear-white-space>
            =~ [^"\\\r]|((\r\n)?[ \t])+

dtext       =  <any CHAR excluding "[", "]", "\" & CR, & including linear-white-space>
            =~ [^][\\\r]|((\r\n)?[ \t])+

quoted-string  =  <"> *(qtext|quoted-pair) <">
               =~ "([^"\\\r]|((\r\n)?[ \t])|\\.)*"
(erratum)      =~ "(\n|(\\\r)*([^"\\\r\n]|\\[^\r]|(\r\n)?[ \t]))*(\\\r)*"

domain-literal =  "[" *(dtext|quoted-pair) "]"
               =~ \[([^][\\\r]|((\r\n)?[ \t])|\\.)*]
(erratum)      =~ \[(\n|(\\\r)*([^][\\\r\n]|\\[^\r]|(\r\n)?[ \t]))*(\\\r)*]

atom        =  1*<any CHAR except specials, SPACE and CTLs>
            =~ [^][()<>@,;:\\". \x00-\x1F\x7F]+

word        =  atom / quoted-string
            =~ [^][()<>@,;:\\". \x00-\x1F\x7F]+|"(\n|(\\\r)*([^"\\\r\n]|\\[^\r]|(\r\n)?[ \t]))*(\\\r)*"

domain-ref  =  atom

sub-domain  =  domain-ref / domain-literal
            =~ [^][()<>@,;:\\". \x00-\x1F\x7F]+|\[(\n|(\\\r)*([^][\\\r\n]|\\[^\r]|(\r\n)?[ \t]))*(\\\r)*]

local-part  =  word *("." word)
            =~ ([^][()<>@,;:\\". \x00-\x1F\x7F]+|"(\n|(\\\r)*([^"\\\r\n]|\\[^\r]|(\r\n)?[ \t]))*(\\\r)*")(\.([^][()<>@,;:\\". \x00-\x1F\x7F]+|"(\n|(\\\r)*([^"\\\r\n]|\\[^\r]|(\r\n)?[ \t]))*(\\\r)*"))*
(opt-lwsp)  =~ ([^][()<>@,;:\\". \x00-\x1F\x7F]+|"(\n|(\\\r)*([^"\\\r\n]|\\[^\r]|(\r\n)?[ \t]))*(\\\r)*")(((\r\n)?[ \t])*\.((\r\n)?[ \t])*([^][()<>@,;:\\". \x00-\x1F\x7F]+|"(\n|(\\\r)*([^"\\\r\n]|\\[^\r]|(\r\n)?[ \t]))*(\\\r)*"))*

domain      =  sub-domain *("." sub-domain)
            =~ ([^][()<>@,;:\\". \x00-\x1F\x7F]+|\[(\n|(\\\r)*([^][\\\r\n]|\\[^\r]|(\r\n)?[ \t]))*(\\\r)*])(\.([^][()<>@,;:\\". \x00-\x1F\x7F]+|\[(\n|(\\\r)*([^][\\\r\n]|\\[^\r]|(\r\n)?[ \t]))*(\\\r)*]))*
(opt-lwsp)  =~ ([^][()<>@,;:\\". \x00-\x1F\x7F]+|\[(\n|(\\\r)*([^][\\\r\n]|\\[^\r]|(\r\n)?[ \t]))*(\\\r)*])(((\r\n)?[ \t])*\.((\r\n)?[ \t])*([^][()<>@,;:\\". \x00-\x1F\x7F]+|\[(\n|(\\\r)*([^][\\\r\n]|\\[^\r]|(\r\n)?[ \t]))*(\\\r)*]))*

addr-spec   =  local-part "@" domain
            =~ ([^][()<>@,;:\\". \x00-\x1F\x7F]+|"(\n|(\\\r)*([^"\\\r\n]|\\[^\r]|(\r\n)?[ \t]))*(\\\r)*")(\.([^][()<>@,;:\\". \x00-\x1F\x7F]+|"(\n|(\\\r)*([^"\\\r\n]|\\[^\r]|(\r\n)?[ \t]))*(\\\r)*"))*@([^][()<>@,;:\\". \x00-\x1F\x7F]+|\[(\n|(\\\r)*([^][\\\r\n]|\\[^\r]|(\r\n)?[ \t]))*(\\\r)*])(\.([^][()<>@,;:\\". \x00-\x1F\x7F]+|\[(\n|(\\\r)*([^][\\\r\n]|\\[^\r]|(\r\n)?[ \t]))*(\\\r)*]))*
(opt-lwsp)  =~ ([^][()<>@,;:\\". \x00-\x1F\x7F]+|"(\n|(\\\r)*([^"\\\r\n]|\\[^\r]|(\r\n)?[ \t]))*(\\\r)*")((\r\n)?[ \t])*(\.((\r\n)?[ \t])*([^][()<>@,;:\\". \x00-\x1F\x7F]+|"(\n|(\\\r)*([^"\\\r\n]|\\[^\r]|(\r\n)?[ \t]))*(\\\r)*")((\r\n)?[ \t])*)*@((\r\n)?[ \t])*([^][()<>@,;:\\". \x00-\x1F\x7F]+|\[(\n|(\\\r)*([^][\\\r\n]|\\[^\r]|(\r\n)?[ \t]))*(\\\r)*])(((\r\n)?[ \t])*\.((\r\n)?[ \t])*([^][()<>@,;:\\". \x00-\x1F\x7F]+|\[(\n|(\\\r)*([^][\\\r\n]|\\[^\r]|(\r\n)?[ \t]))*(\\\r)*]))*
(canonical) =~ ([^][()<>@,;:\\". \x00-\x1F\x7F]+|"(\n|(\\\r)*([^"\\\r\n]|\\[^\r]))*(\\\r)*")(\.([^][()<>@,;:\\". \x00-\x1F\x7F]+|"(\n|(\\\r)*([^"\\\r\n]|\\[^\r]))*(\\\r)*"))*@([^][()<>@,;:\\". \x00-\x1F\x7F]+|\[(\n|(\\\r)*([^][\\\r\n]|\\[^\r]))*(\\\r)*])(\.([^][()<>@,;:\\". \x00-\x1F\x7F]+|\[(\n|(\\\r)*([^][\\\r\n]|\\[^\r]))*(\\\r)*]))*

RFC 5322

Я прийшов до наступного регулярного виразу. Запрошую всіх спробувати розбити. Якщо ви знайдете помилкові позитиви чи помилкові негативи, будь ласка, опублікуйте їх у коментарі, і я спробую виправити вираз якомога швидше.

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

Я вважаю, що він повністю відповідає RFC 5322, включаючи errata . Він розпізнає лише адреси електронної пошти у їхній канонічній формі. Зворотний вираз, який розпізнає (складений) пробіл, див. Виведення нижче.

Виведення показує, як я дійшов до виразу. Я перераховую всі відповідні граматичні правила з RFC саме так, як вони з'являються, а потім відповідне регулярне вираження. Для правил, що включають семантично нерелевантні (складні) пробіли, я даю окремий регекс із позначкою "(нормалізовано)", який не приймає цю пробіл.

Я проігнорував усі "незрозумілі" правила з RFC. Це означає, що регулярні вирази відповідають лише електронним адресам, які суворо відповідають стандартам RFC 5322. Якщо вам доведеться відповідати "старим" адресам (як це втрачає граматика, включаючи правила "obs-"), ви можете використовувати один з регекерів RFC 822 з попереднього абзацу.

VCHAR           =   %x21-7E
                =~  [!-~]

ALPHA           =   %x41-5A / %x61-7A
                =~  [A-Za-z]

DIGIT           =   %x30-39
                =~  [0-9]

HTAB            =   %x09
                =~  \t

CR              =   %x0D
                =~  \r

LF              =   %x0A
                =~  \n

SP              =   %x20
                =~  

DQUOTE          =   %x22
                =~  "

CRLF            =   CR LF
                =~  \r\n

WSP             =   SP / HTAB
                =~  [\t ]

quoted-pair     =   "\" (VCHAR / WSP)
                =~  \\[\t -~]

FWS             =   ([*WSP CRLF] 1*WSP)
                =~  ([\t ]*\r\n)?[\t ]+

ctext           =   %d33-39 / %d42-91 / %d93-126
                =~  []!-'*-[^-~]

("comment" is left out in the regex)
ccontent        =   ctext / quoted-pair / comment
                =~  []!-'*-[^-~]|(\\[\t -~])

(not regular)
comment         =   "(" *([FWS] ccontent) [FWS] ")"

(is equivalent to FWS when leaving out comments)
CFWS            =   (1*([FWS] comment) [FWS]) / FWS
                =~  ([\t ]*\r\n)?[\t ]+

atext           =   ALPHA / DIGIT / "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "/" / "=" / "?" / "^" / "_" / "`" / "{" / "|" / "}" / "~"
                =~  [-!#-'*+/-9=?A-Z^-~]

dot-atom-text   =   1*atext *("." 1*atext)
                =~  [-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*

dot-atom        =   [CFWS] dot-atom-text [CFWS]
                =~  (([\t ]*\r\n)?[\t ]+)?[-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*(([\t ]*\r\n)?[\t ]+)?
(normalized)    =~  [-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*

qtext           =   %d33 / %d35-91 / %d93-126
                =~  []!#-[^-~]

qcontent        =   qtext / quoted-pair
                =~  []!#-[^-~]|(\\[\t -~])

(erratum)
quoted-string   =   [CFWS] DQUOTE ((1*([FWS] qcontent) [FWS]) / FWS) DQUOTE [CFWS]
                =~  (([\t ]*\r\n)?[\t ]+)?"(((([\t ]*\r\n)?[\t ]+)?([]!#-[^-~]|(\\[\t -~])))+(([\t ]*\r\n)?[\t ]+)?|(([\t ]*\r\n)?[\t ]+)?)"(([\t ]*\r\n)?[\t ]+)?
(normalized)    =~  "([]!#-[^-~ \t]|(\\[\t -~]))+"

dtext           =   %d33-90 / %d94-126
                =~  [!-Z^-~]

domain-literal  =   [CFWS] "[" *([FWS] dtext) [FWS] "]" [CFWS]
                =~  (([\t ]*\r\n)?[\t ]+)?\[((([\t ]*\r\n)?[\t ]+)?[!-Z^-~])*(([\t ]*\r\n)?[\t ]+)?](([\t ]*\r\n)?[\t ]+)?
(normalized)    =~  \[[\t -Z^-~]*]

local-part      =   dot-atom / quoted-string
                =~  (([\t ]*\r\n)?[\t ]+)?[-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*(([\t ]*\r\n)?[\t ]+)?|(([\t ]*\r\n)?[\t ]+)?"(((([\t ]*\r\n)?[\t ]+)?([]!#-[^-~]|(\\[\t -~])))+(([\t ]*\r\n)?[\t ]+)?|(([\t ]*\r\n)?[\t ]+)?)"(([\t ]*\r\n)?[\t ]+)?
(normalized)    =~  [-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*|"([]!#-[^-~ \t]|(\\[\t -~]))+"

domain          =   dot-atom / domain-literal
                =~  (([\t ]*\r\n)?[\t ]+)?[-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*(([\t ]*\r\n)?[\t ]+)?|(([\t ]*\r\n)?[\t ]+)?\[((([\t ]*\r\n)?[\t ]+)?[!-Z^-~])*(([\t ]*\r\n)?[\t ]+)?](([\t ]*\r\n)?[\t ]+)?
(normalized)    =~  [-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*|\[[\t -Z^-~]*]

addr-spec       =   local-part "@" domain
                =~  ((([\t ]*\r\n)?[\t ]+)?[-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*(([\t ]*\r\n)?[\t ]+)?|(([\t ]*\r\n)?[\t ]+)?"(((([\t ]*\r\n)?[\t ]+)?([]!#-[^-~]|(\\[\t -~])))+(([\t ]*\r\n)?[\t ]+)?|(([\t ]*\r\n)?[\t ]+)?)"(([\t ]*\r\n)?[\t ]+)?)@((([\t ]*\r\n)?[\t ]+)?[-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*(([\t ]*\r\n)?[\t ]+)?|(([\t ]*\r\n)?[\t ]+)?\[((([\t ]*\r\n)?[\t ]+)?[!-Z^-~])*(([\t ]*\r\n)?[\t ]+)?](([\t ]*\r\n)?[\t ]+)?)
(normalized)    =~  ([-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*|"([]!#-[^-~ \t]|(\\[\t -~]))+")@([-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*|\[[\t -Z^-~]*])

Зауважте, що деякі джерела (зокрема w3c ) стверджують, що RFC 5322 занадто суворий щодо локальної частини (тобто частини до @ -сигналу). Це тому, що "..", "a..b" і "a". не є дійсними атомами крапок, хоча вони можуть використовуватися як назви поштових скриньок. RFC, однак, це дозволить місцевим частинам , як це, за винятком того, що вони повинні бути укладені в лапки. Тож замість a..b@example.netвас слід писати "a..b"@example.net, що семантично рівнозначно.

Подальші обмеження

SMTP (як визначено в RFC 5321 ) додатково обмежує набір дійсних адрес електронної пошти (або власне: імена поштової скриньки). Здається розумним нав'язувати цю більш сувору граматику, щоб відповідна електронна адреса була фактично використана для надсилання електронної пошти.

RFC 5321 в основному залишає в спокої "локальну" частину (тобто частину до @ -сигналу), але суворіше щодо доменної частини (тобто частини після @ -сигналу). Він дозволяє лише імена хостів замість точкових атомів та адреси літералів замість літералів домену.

Граматика, представлена ​​в RFC 5321, занадто поблажлива, якщо мова йде про імена хостів та IP адреси. Я взяв на себе сміливість "виправляти" відповідні правила, використовуючи цей проект та RFC 1034 як керівництво. Ось отриманий вираз.

([-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*|"([]!#-[^-~ \t]|(\\[\t -~]))+")@([0-9A-Za-z]([0-9A-Za-z-]{0,61}[0-9A-Za-z])?(\.[0-9A-Za-z]([0-9A-Za-z-]{0,61}[0-9A-Za-z])?)*|\[((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|IPv6:((((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){6}|::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){5}|[0-9A-Fa-f]{0,4}::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){4}|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):)?(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){3}|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,2}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){2}|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,3}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,4}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::)((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3})|(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3})|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,5}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3})|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,6}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::)|(?!IPv6:)[0-9A-Za-z-]*[0-9A-Za-z]:[!-Z^-~]+)])

Зауважте, що залежно від випадку використання ви, можливо, не захочете дозволити "генеральний адрес-буквальний" у вашому регексе. Також зауважте, що я використовував негативну підказку (?!IPv6:)в остаточному регулярному виразі, щоб запобігти збігу частини "General-address-literal" у відповідність неправильним IPv6 адресам. Деякі процесори регулярного вираження не підтримують негативний пошук. Видаліть підрядку|(?!IPv6:)[0-9A-Za-z-]*[0-9A-Za-z]:[!-Z^-~]+ з регулярного виразу, якщо ви хочете вийняти всю частину "Загальна адреса-буквальний".

Ось виведення:

Let-dig         =   ALPHA / DIGIT
                =~  [0-9A-Za-z]

Ldh-str         =   *( ALPHA / DIGIT / "-" ) Let-dig
                =~  [0-9A-Za-z-]*[0-9A-Za-z]

(regex is updated to make sure sub-domains are max. 63 charactes long - RFC 1034 section 3.5)
sub-domain      =   Let-dig [Ldh-str]
                =~  [0-9A-Za-z]([0-9A-Za-z-]{0,61}[0-9A-Za-z])?

Domain          =   sub-domain *("." sub-domain)
                =~  [0-9A-Za-z]([0-9A-Za-z-]{0,61}[0-9A-Za-z])?(\.[0-9A-Za-z]([0-9A-Za-z-]{0,61}[0-9A-Za-z])?)*

Snum            =   1*3DIGIT
                =~  [0-9]{1,3}

(suggested replacement for "Snum")
ip4-octet       =   DIGIT / %x31-39 DIGIT / "1" 2DIGIT / "2" %x30-34 DIGIT / "25" %x30-35
                =~  25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9]

IPv4-address-literal    =   Snum 3("."  Snum)
                        =~  [0-9]{1,3}(\.[0-9]{1,3}){3}

(suggested replacement for "IPv4-address-literal")
ip4-address     =   ip4-octet 3("." ip4-octet)
                =~  (25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}

(suggested replacement for "IPv6-hex")
ip6-h16         =   "0" / ( (%x49-57 / %x65-70 /%x97-102) 0*3(%x48-57 / %x65-70 /%x97-102) )
                =~  0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}

(not from RFC)
ls32            =   ip6-h16 ":" ip6-h16 / ip4-address
                =~  (0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3})|(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}

(suggested replacement of "IPv6-addr")
ip6-address     =                                      6(ip6-h16 ":") ls32
                    /                             "::" 5(ip6-h16 ":") ls32
                    / [                 ip6-h16 ] "::" 4(ip6-h16 ":") ls32
                    / [ *1(ip6-h16 ":") ip6-h16 ] "::" 3(ip6-h16 ":") ls32
                    / [ *2(ip6-h16 ":") ip6-h16 ] "::" 2(ip6-h16 ":") ls32
                    / [ *3(ip6-h16 ":") ip6-h16 ] "::"   ip6-h16 ":"  ls32
                    / [ *4(ip6-h16 ":") ip6-h16 ] "::"                ls32
                    / [ *5(ip6-h16 ":") ip6-h16 ] "::"   ip6-h16
                    / [ *6(ip6-h16 ":") ip6-h16 ] "::"
                =~  (((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){6}|::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){5}|[0-9A-Fa-f]{0,4}::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){4}|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):)?(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){3}|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,2}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){2}|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,3}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,4}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::)((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3})|(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3})|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,5}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3})|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,6}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::

IPv6-address-literal    =   "IPv6:" ip6-address
                        =~  IPv6:((((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){6}|::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){5}|[0-9A-Fa-f]{0,4}::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){4}|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):)?(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){3}|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,2}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){2}|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,3}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,4}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::)((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3})|(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3})|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,5}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3})|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,6}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::)

Standardized-tag        =   Ldh-str
                        =~  [0-9A-Za-z-]*[0-9A-Za-z]

dcontent        =   %d33-90 / %d94-126
                =~  [!-Z^-~]

General-address-literal =   Standardized-tag ":" 1*dcontent
                        =~  [0-9A-Za-z-]*[0-9A-Za-z]:[!-Z^-~]+

address-literal =   "[" ( IPv4-address-literal / IPv6-address-literal / General-address-literal ) "]"
                =~  \[((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|IPv6:((((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){6}|::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){5}|[0-9A-Fa-f]{0,4}::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){4}|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):)?(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){3}|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,2}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){2}|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,3}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,4}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::)((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3})|(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3})|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,5}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3})|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,6}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::)|(?!IPv6:)[0-9A-Za-z-]*[0-9A-Za-z]:[!-Z^-~]+)]

Mailbox         =   Local-part "@" ( Domain / address-literal )
                =~  ([-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*|"([]!#-[^-~ \t]|(\\[\t -~]))+")@([0-9A-Za-z]([0-9A-Za-z-]{0,61}[0-9A-Za-z])?(\.[0-9A-Za-z]([0-9A-Za-z-]{0,61}[0-9A-Za-z])?)*|\[((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|IPv6:((((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){6}|::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){5}|[0-9A-Fa-f]{0,4}::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){4}|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):)?(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){3}|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,2}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){2}|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,3}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,4}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::)((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3})|(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3})|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,5}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3})|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,6}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::)|(?!IPv6:)[0-9A-Za-z-]*[0-9A-Za-z]:[!-Z^-~]+)])

Перевірка введення користувачем

Поширеним випадком використання є перевірка введення користувачем, наприклад, у формі html. У такому випадку зазвичай доцільно виключати адреси-літерали та вимагати принаймні дві мітки в імені хоста. Взявши за основу вдосконалений регулярний вираз RFC 5321 з попереднього розділу, отриманим виразом буде:

([-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*|"([]!#-[^-~ \t]|(\\[\t -~]))+")@[0-9A-Za-z]([0-9A-Za-z-]{0,61}[0-9A-Za-z])?(\.[0-9A-Za-z]([0-9A-Za-z-]{0,61}[0-9A-Za-z])?)+

Я не рекомендую більше обмежувати локальну частину, наприклад, виключаючи рядки, що цитуються, оскільки ми не знаємо, які імена поштових скриньок деякі хости дозволяють (як, "a..b"@example.netчи навіть "a b"@example.net).

Я також не рекомендую чітко підтверджувати список буквальних доменів верхнього рівня або навіть встановлювати обмеження по довжині (пам'ятайте, як ".museum" недійсний [a-z]{2,4}), але якщо вам потрібно:

([-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*|"([]!#-[^-~ \t]|(\\[\t -~]))+")@([0-9A-Za-z]([0-9A-Za-z-]{0,61}[0-9A-Za-z])?\.)*(net|org|com|info|тощо ...)

Переконайтеся, що ви регулярно використовуєте регулярний вираз, якщо ви вирішите піти по шляху явної перевірки домену верхнього рівня.

Подальші міркування

Якщо ви приймаєте лише імена хостів у частині домену (після @ -сигналу), вищевказані символи приймають лише мітки з максимум 63 символами, як слід. Однак вони не примушують до того, що все ім’я хоста повинно бути не більше 253 символів (включаючи крапки). Незважаючи на те, що це обмеження суворо говорить, як і раніше регулярно, не можливо здійснити регулярний вираз, який містить це правило.

Інший розгляд, особливо при використанні регулярних виразів для перевірки вводу, - це зворотній зв'язок з користувачем. Якщо користувач вводить неправильну адресу, було б непогано дати трохи більше відгуків, ніж проста "синтаксично неправильна адреса". З регексами "ваніль" це неможливо.

Ці два міркування можна вирішити шляхом розбору адреси. Обмеження додаткової довжини на імена хостів в деяких випадках також може бути усунено за допомогою додаткового регулярного вираження, який перевіряє його, та співставлення адреси з обома виразами.

Жоден реджекс у цій відповіді не оптимізований для продуктивності. Якщо продуктивність не викликає труднощів, слід дізнатися, чи можна оптимізувати (і як) регекс на ваш вибір.


3
RFC 6532 оновлює 5322, щоб дозволити та включити повний чистий UTF-8. Додаткову інформацію тут .

Згідно із вікіпедією, схоже, що локальна частина, коли поставлена ​​пунктиром, має обмеження на 64 символи на частину, а також RFC 5322 посилається на пунктирну локальну частину, яку слід інтерпретувати з обмеженнями доменів. Наприклад, arbitrary-long-email-address-should-be-invalid-arbitrary-long-email-address-should-be-invalid.and-the-second-group-also-should-not-be-so-long-and-the-second-group-also-should-not-be-so-long@example.comне слід підтверджувати. Я пропоную змінити знаки "+" у першій групі (назва перед необов'язковою точкою), а у другій групі (назва після наступних крапок) на{1,64}
Хаві Монтеро

Оскільки коментарі обмежені за розміром, ось наведений я регулярний вираз, який я планую використовувати, який є на початку цієї відповіді, плюс обмеження розміру в локальній частині, плюс додавання зворотньої косої риски до "/" символ відповідно до вимог PHP, а також у regex101.com: У PHP я використовую:$emailRegex = '/^([-!#-\'*+\/-9=?A-Z^-~]{1,64}(\.[-!#-\'*+\/-9=?A-Z^-~]{1,64})*|"([]!#-[^-~ \t]|(\\[\t -~]))+")@[0-9A-Za-z]([0-9A-Za-z-]{0,61}[0-9A-Za-z])?(\.[0-9A-Za-z]([0-9A-Za-z-]{0,61}[0-9A-Za-z])?)+$/';
Xavi Montero

ПОПЕРЕДЖЕННЯ: чомусь StackOverflow додає приховані символи під час копіювання з відображеної розмітки. Скопіюйте його в regex101.com і там ви побачите чорні точки. Ви повинні їх вилучити та виправити рядок ... Можливо, якщо інтегровано у відповідь, там вони правильно скопійовані. Вибачте за незручності. Я не хочу додавати нову відповідь, оскільки ця є правильною. Також я не хочу безпосередньо редагувати, якщо громада не вважає, що це має бути інтегровано в неї.
Хаві Монтеро

@XaviMontero Thaks за участь у Xavi! Чи є у вас посилання на RFC із зазначенням обмеження на 64 символи на локальних етикетках деталей? Якщо так, я б із задоволенням скорегував відповідь.
Рінке

73

У мережі є чимало прикладів цього (і я думаю, навіть такий, що повністю підтверджує RFC - але це довгі десятки / сотні рядків, якщо служить пам'ять). Люди, як правило, захоплюються підтвердженням подібних речей. Чому б просто не перевірити, чи є він @ і принаймні один. і відповідає простої мінімальної довжини. Ввести фальшивий електронний лист і все одно відповідати будь-якому дійсному регулярному вираженню. Я б здогадався, що помилкові позитиви є кращими за хибні негативи.


1
Так, але який RFC? :) Цей [RFC-5322 – валідатор] ( stackoverflow.com/questions/201323/… ) довжиною лише сорок рядків.
tchrist

14
А. не потрібно. У TLD може бути адреса електронної пошти, або може бути адреса IPv6
Sijmen Mulder

1
RFC - це не кінець історії: ICANN більше не дозволяє доменів "без проблем": icann.org/news/announcement-2013-08-30-en
синхронізація

64

Вирішуючи, які символи дозволені, пам’ятайте про своїх апострофах та дефісах. Я не маю контролю над тим, що моя компанія генерує мою електронну адресу, використовуючи моє ім’я із системи управління персоналом. Це включає апостроф на моє прізвище. Я не можу сказати, скільки разів мені було заборонено взаємодіяти з веб-сайтом через те, що моя електронна адреса "недійсна".


4
Це надзвичайно поширена проблема в програмах, які роблять необґрунтовані припущення щодо того, що є, а що не дозволяється в імені людини. Не слід робити таких припущень, просто прийміть будь-який символ, про який відповідні RFC (и) говорять, що треба.
tchrist

4
Так. Мене особливо люблять програмисти, які відкидають великі літери в електронні адреси! Нерозумно та / або ліниво.
PhiLho

63

Цей регекс походить з електронної пошти Perl :: Дійсна бібліотека. Я вважаю, що це найточніше, він відповідає всім 822. І він заснований на регулярному вираженні книги О'Рейлі:

Регулярне вираження, побудоване на прикладі Джефрі Фрідла в « Освоєнні регулярних виразів» ( http://www.ora.com/catalog/regexp/ ).

$RFC822PAT = <<'EOF';
[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\
xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xf
f\n\015()]*)*\)[\040\t]*)*(?:(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\x
ff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|"[^\\\x80-\xff\n\015
"]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015"]*)*")[\040\t]*(?:\([^\\\x80-\
xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80
-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*
)*(?:\.[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\
\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\
x80-\xff\n\015()]*)*\)[\040\t]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x8
0-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|"[^\\\x80-\xff\n
\015"]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015"]*)*")[\040\t]*(?:\([^\\\x
80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^
\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040
\t]*)*)*@[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([
^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\
\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\
x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|\[(?:[^\\\x80-
\xff\n\015\[\]]|\\[^\x80-\xff])*\])[\040\t]*(?:\([^\\\x80-\xff\n\015()
]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\
x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:\.[\04
0\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\
n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\
015()]*)*\)[\040\t]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?!
[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|\[(?:[^\\\x80-\xff\n\015\[\
]]|\\[^\x80-\xff])*\])[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\
x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\01
5()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*)*|(?:[^(\040)<>@,;:".
\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]
)|"[^\\\x80-\xff\n\015"]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015"]*)*")[^
()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037]*(?:(?:\([^\\\x80-\xff\n\0
15()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][
^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)|"[^\\\x80-\xff\
n\015"]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015"]*)*")[^()<>@,;:".\\\[\]\
x80-\xff\000-\010\012-\037]*)*<[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?
:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-
\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:@[\040\t]*
(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015
()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()
]*)*\)[\040\t]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\0
40)<>@,;:".\\\[\]\000-\037\x80-\xff])|\[(?:[^\\\x80-\xff\n\015\[\]]|\\
[^\x80-\xff])*\])[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\
xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*
)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:\.[\040\t]*(?:\([^\\\x80
-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x
80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t
]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\
\[\]\000-\037\x80-\xff])|\[(?:[^\\\x80-\xff\n\015\[\]]|\\[^\x80-\xff])
*\])[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x
80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80
-\xff\n\015()]*)*\)[\040\t]*)*)*(?:,[\040\t]*(?:\([^\\\x80-\xff\n\015(
)]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\
\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*@[\040\t
]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\0
15()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015
()]*)*\)[\040\t]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(
\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|\[(?:[^\\\x80-\xff\n\015\[\]]|
\\[^\x80-\xff])*\])[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80
-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()
]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:\.[\040\t]*(?:\([^\\\x
80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^
\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040
\t]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".
\\\[\]\000-\037\x80-\xff])|\[(?:[^\\\x80-\xff\n\015\[\]]|\\[^\x80-\xff
])*\])[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\
\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x
80-\xff\n\015()]*)*\)[\040\t]*)*)*)*:[\040\t]*(?:\([^\\\x80-\xff\n\015
()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\
\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*)?(?:[^
(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-
\037\x80-\xff])|"[^\\\x80-\xff\n\015"]*(?:\\[^\x80-\xff][^\\\x80-\xff\
n\015"]*)*")[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|
\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))
[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:\.[\040\t]*(?:\([^\\\x80-\xff
\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\x
ff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(
?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\
000-\037\x80-\xff])|"[^\\\x80-\xff\n\015"]*(?:\\[^\x80-\xff][^\\\x80-\
xff\n\015"]*)*")[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\x
ff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)
*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*)*@[\040\t]*(?:\([^\\\x80-\x
ff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-
\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)
*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\
]\000-\037\x80-\xff])|\[(?:[^\\\x80-\xff\n\015\[\]]|\\[^\x80-\xff])*\]
)[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-
\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\x
ff\n\015()]*)*\)[\040\t]*)*(?:\.[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(
?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80
-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:[^(\040)<
>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x8
0-\xff])|\[(?:[^\\\x80-\xff\n\015\[\]]|\\[^\x80-\xff])*\])[\040\t]*(?:
\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]
*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)
*\)[\040\t]*)*)*>)
EOF

14
O_O вам також знадобиться бути майстром регулярних виразів, щоб зрозуміти, що це робить
Кріс МакГрат

45

Як ви пишете в PHP, я б радив вам використовувати перевірку вбудованої PHP для електронних листів.

filter_var($value, FILTER_VALIDATE_EMAIL)

Якщо ви використовуєте php-версію нижче 5.3.6, будь ласка, пам’ятайте про цю проблему: https://bugs.php.net/bug.php?id=53091

Якщо ви хочете отримати додаткову інформацію про те, як працює ця перевірка вбудованих програм, дивіться тут: Чи справді працює PHP filter_var FILTER_VALIDATE_EMAIL?


отримує голосування, саме те, що я збирався сказати. Не обробляє IDN, але перетворює їх на попередній код заздалегідь вирішує це. PHP> = 5.3 має idn_to_ascii () для цього. Один з найкращих і найпростіших способів перевірки електронної пошти.
Тейлор

43

Cal Henderson (Flickr) написав статтю під назвою Розбір електронних адрес в PHP і показує, як зробити належний розбір сумісних з RFC (2) 822 адресами електронної пошти. Ви також можете отримати вихідний код у php , python та ruby, який має ліцензію на cc .


мені сказали, що a@bце дійсно
dsdsdsdsd

1
@dsdsdsdsd Тому що a@bце дійсно ... у цьому випадку bдомен верхнього рівня.
rink.attendant.6

42

Я ніколи не заважаю творити власним регулярним виразом, тому що ймовірно, що хтось уже придумав кращу версію. Я завжди використовую regexlib, щоб знайти свій смак.


1
Це було позначено за довжиною та змістом, але він все ще є добрим внеском із 41 голосом, і його не слід видаляти.
Буде

37

Немає такої, яка справді придатна для використання.
Я обговорюю деякі проблеми у своїй відповіді на питання: Чи існує бібліотека php для перевірки електронної адреси? , це також обговорюється в Regexp розпізнавання електронної адреси важко?

Коротше кажучи, не сподівайтесь, що один корисний регулярний вираз виконає належну роботу. І найкращий регулярний вираз буде підтверджувати синтаксис, а не дійсність електронної пошти (jhohn@example.com правильна, але, ймовірно, відмовиться ...).


Виправте мене, якщо я помиляюся, але я вважаю, що PHP використовує схеми PCRE. Якщо так, ви зможете створити щось подібне до моделі RFC 5322 Abigail .
tchrist

@tchrist: не впевнений, чи PCRE натрапив на цей синтаксис (який я виявляю). Якщо так, то не впевнений, чи PHRE's PCRE натрапив на цю версію PCRE ... Ну, якщо я правильно зрозумів цей синтаксис, ви можете також використовувати PEG-аналізатор, набагато чіткіший і повніший, ніж регулярний вираз.
PhiLho

PCRE вже наздогнав його, але , можливо , PHP не наздогнали PCRE. ☹
tchrist

36

Одним простим регулярним виразом, який хоча б не відкидає жодну дійсну адресу електронної пошти, буде перевірка наявності чогось, після чого знак @, а потім щось, що супроводжується періодом і принаймні 2 сотами. Він нічого не відхилить, але переглянувши специфікацію, я не можу знайти жодного електронного листа, який би був дійсним та відхиленим.

email = ~ /.+@[^@]+\.[^@]{2,}$/


3
Це те, що я шукав. Не дуже обмежує, але переконується, що є лише 1 @ (оскільки ми розбираємо список і хочемо переконатися, що немає відсутніх коми). FYI, ви можете мати @ ліворуч, якщо це в лапках: Valid_email_addresses , але це досить бахромою.
Джош

2
Після його використання зрозумів, що він не працює точно. /^[^@]+@[^@]+\.[^@]{2}[^@]*$/ насправді перевіряє наявність знака 1 @. Ваш регекс пропустить кілька разів через. * Наприкінці.
Джош

1
Правильно. Я не намагаюся відхилити всі недійсні, просто не відхиляйте дійсну адресу електронної пошти.
шпигун

1
Це було б набагато краще використовувати це: /^[^@]+@[^@]+\.[^@]{2,4}$/переконайтеся, що він закінчується від 2 до 4 символів, які не належать @. Як зазначав @Josh, це дозволяє в кінцевому підсумку отримати додатковий @. Але ви також можете змінити це так: /^[^@]+@[^@]+\.[^a-z-A-Z]{2,4}$/оскільки всі домени верхнього рівня - це символи aZ. ви можете замінити 4з 5або більш дозволяючи доменів верхнього рівня імена , щоб бути більше в майбутньому.
ЛЕТИ

@FLY, ka @ foo. повертається правильно. Це, за стандартами, передбачається?
SexyBeast

29

Ви можете використовувати той, який використовується плагіном jQuery Validation:

/^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i

це, здається, робить гарну роботу. Це дозволило: a-b'c_d.e@f-g.hале вдалося спіймати невідповідні варіанти, такі як a-b'c_d.@f-g.hіa-b'c_d.e@f-.h
dsdsdsdsd

25

Для найбільш повної оцінки найкращого регулярного вираження для перевірки адреси електронної пошти перейдіть за цим посиланням; " Порівняння електронної адреси, що підтверджує регулярні вирази "

Ось поточний верхній вираз для довідкових цілей:

/^([\w\!\#$\%\&\'\*\+\-\/\=\?\^\`{\|\}\~]+\.)*[\w\!\#$\%\&\'\*\+\-\/\=\?\^\`{\|\}\~]+@((((([a-z0-9]{1}[a-z0-9\-]{0,62}[a-z0-9]{1})|[a-z])\.)+[a-z]{2,6})|(\d{1,3}\.){3}\d{1,3}(\:\d{1,5})?)$/i

ложка16: Це посилання насправді не правильне. Його твердження про те, що не може бути ідеального зразка для перевірки адрес електронної пошти, є явною помилкою. Ви можете , але ви повинні переконатися, що ви слідуєте RFC аж до листа. І ви також повинні вибрати правильний RFC.
tchrist

"Найкращий" зараз не працює з jage regex - навіть після належного втечі та перетворення рядка.
Ерік Чен

23

Не кажучи вже про те, що нелатинські (китайські, арабські, грецькі, івритські, кириличні тощо) доменні імена мають бути дозволені найближчим часом . Кожен повинен змінити використаний регулярний вимір електронної пошти, тому що ці символи, безумовно, не повинні охоплюватись [a-z]/iні\w . Усі вони провалюються.

Зрештою, найкращий спосіб підтвердити адресу електронної пошти - це все-таки фактично надіслати електронний лист на відповідну адресу, щоб підтвердити адресу. Якщо адреса електронної пошти є частиною автентифікації користувача (зареєструватися / вхід / тощо), ви можете ідеально поєднати її з системою активації користувача. Тобто надсилайте електронний лист із посиланням унікальним ключем активації на вказану адресу електронної пошти та дозволяйте входити в систему лише тоді, коли користувач активував новостворений обліковий запис за допомогою посилання в електронній пошті.

Якщо метою регулярного вираження є просто швидке інформування користувача в інтерфейсі про те, що вказана адреса електронної пошти не схожа на потрібний формат, краще все-таки перевірити, чи відповідає вона в основному такому регексу:

^([^.@]+)(\.[^.@]+)*@([^.@]+\.)+([^.@]+)$

Просто як це. Чому на землі ви б не піклувалися про символи, які використовуються в імені та домені? Це обов'язок клієнта вводити дійсну адресу електронної пошти, а не серверну. Навіть коли клієнт вводить синтаксично дійсну адресу електронної пошти на кшталт aa@bb.cc, це не гарантує, що це законна електронна адреса. Жоден регекс не може цього покрити.


4
Я погоджуюсь, що відправлення повідомлення про автентифікацію зазвичай є найкращим способом для подібних матеріалів, синтаксично правильне та дійсне - це не те саме. Мене засмучує, коли я змушую вводити свою електронну адресу двічі для "Підтвердження", як ніби не можу дивитись на те, що я ввів. Я все-таки копіюю лише перший на другий, він, здається, все більше використовується.
PeteT

згоден! але цей регулярний вираз я не вважаю коректним, оскільки він дозволяє spacesпісля @.напр. test@test.ca com netвважаємо дійсним електронний лист, використовуючи вищевказаний регулярний вираз, де він повинен повертатися недійсним.
CB4

20

Специфікація HTML5 пропонує простий регулярний вираз для перевірки адрес електронної пошти:

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

Це навмисно не відповідає стандарту RFC 5322 .

Примітка: Ця вимога є навмисним порушенням в RFC 5322 , який визначає синтаксис для адрес електронної пошти, яка одночасно занадто строго (до @символу), занадто розпливчасті (після @символу), і занадто слабким ( з урахуванням коментарів, пробільні символи, і цитуються рядки в незнайомих для більшості користувачів способах), щоб бути тут корисними.

Загальна довжина також може бути обмежена 254 символами на RFC 3696 errata 1690 .


Найкраща відповідь! Ось посилання на рекомендацію w3: w3.org/TR/html5/forms.html#valid-e-mail-address Цей регулярний вираз використовується у багатьох браузерах.
Райан Тейлор

3
Це ТАК не найкраща відповідь! Ця модель відповідає цьому абсолютно неприпустимого адресою: invalid@emailaddress. Я б закликав до обережності та багато тестування, перш ніж використовувати його!
Шерідан

@Sheridan, якщо ви думаєте, що існує проблема зі специфікацією HTML5, ви можете порушити проблему тут: github.com/w3c/html/isissue
Luna

Це не надто додає stackoverflow.com/a/8829363, і IMHO стане кращим як редагування або коментар до цього.

example @ localhost є дійсним, але для програми в реальному світі ви можете застосувати розширення домену, все, що вам потрібно зробити, - це змінити остаточний * на +, щоб досягти цього (змінивши цю частину шаблону з 0+ на 1+ )
Мітч Сатвелл

15

Для яскравої демонстрації такий монстр є досить хорошим, але все ще не розпізнає правильно всі синтаксично дійсні адреси електронної пошти: він розпізнає вкладені коментарі глибиною до чотирьох рівнів.

Це завдання для аналізатора, але навіть якщо адреса є синтаксично дійсною, вона все одно може бути недоступною. Іноді доводиться вдаватися до гібридного методу "Ей, всі, дивись е-нас!"

// derivative of work with the following copyright and license:
// Copyright (c) 2004 Casey West.  All rights reserved.
// This module is free software; you can redistribute it and/or
// modify it under the same terms as Perl itself.

// see http://search.cpan.org/~cwest/Email-Address-1.80/

private static string gibberish = @"
(?-xism:(?:(?-xism:(?-xism:(?-xism:(?-xism:(?-xism:(?-xism:\
s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[^
\x0A\x0D]))|(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+))
|(?-xism:\\(?-xism:[^\x0A\x0D]))|)+)*\s*\)\s*))+)*\s*\)\s*)+
|\s+)*[^\x00-\x1F\x7F()<>\[\]:;@\,.<DQ>\s]+(?-xism:(?-xism:\
s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[^
\x0A\x0D]))|(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+))
|(?-xism:\\(?-xism:[^\x0A\x0D]))|)+)*\s*\)\s*))+)*\s*\)\s*)+
|\s+)*)|(?-xism:(?-xism:(?-xism:\s*\((?:\s*(?-xism:(?-xism:(
?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|(?-xism:\s*\((?
:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x
0D]))|)+)*\s*\)\s*))+)*\s*\)\s*)+|\s+)*<DQ>(?-xism:(?-xism:[
^\\<DQ>])|(?-xism:\\(?-xism:[^\x0A\x0D])))+<DQ>(?-xism:(?-xi
sm:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xis
m:[^\x0A\x0D]))|(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\
]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|)+)*\s*\)\s*))+)*\s*\)\
s*)+|\s+)*))+)?(?-xism:(?-xism:(?-xism:\s*\((?:\s*(?-xism:(?
-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|(?-xism:
\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[
^\x0A\x0D]))|)+)*\s*\)\s*))+)*\s*\)\s*)+|\s+)*<(?-xism:(?-xi
sm:(?-xism:(?-xism:(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^(
)\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|(?-xism:\s*\((?:\s*(
?-xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))
|)+)*\s*\)\s*))+)*\s*\)\s*)+|\s+)*(?-xism:[^\x00-\x1F\x7F()<
>\[\]:;@\,.<DQ>\s]+(?:\.[^\x00-\x1F\x7F()<>\[\]:;@\,.<DQ>\s]
+)*)(?-xism:(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+))
|(?-xism:\\(?-xism:[^\x0A\x0D]))|(?-xism:\s*\((?:\s*(?-xism:
(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|)+)*\s
*\)\s*))+)*\s*\)\s*)+|\s+)*)|(?-xism:(?-xism:(?-xism:\s*\((?
:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x
0D]))|(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xi
sm:\\(?-xism:[^\x0A\x0D]))|)+)*\s*\)\s*))+)*\s*\)\s*)+|\s+)*
<DQ>(?-xism:(?-xism:[^\\<DQ>])|(?-xism:\\(?-xism:[^\x0A\x0D]
)))+<DQ>(?-xism:(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\
]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|(?-xism:\s*\((?:\s*(?-x
ism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|)+
)*\s*\)\s*))+)*\s*\)\s*)+|\s+)*))\@(?-xism:(?-xism:(?-xism:(
?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?
-xism:[^\x0A\x0D]))|(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^
()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|)+)*\s*\)\s*))+)*\s
*\)\s*)+|\s+)*(?-xism:[^\x00-\x1F\x7F()<>\[\]:;@\,.<DQ>\s]+(
?:\.[^\x00-\x1F\x7F()<>\[\]:;@\,.<DQ>\s]+)*)(?-xism:(?-xism:
\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[
^\x0A\x0D]))|(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+)
)|(?-xism:\\(?-xism:[^\x0A\x0D]))|)+)*\s*\)\s*))+)*\s*\)\s*)
+|\s+)*)|(?-xism:(?-xism:(?-xism:\s*\((?:\s*(?-xism:(?-xism:
(?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|(?-xism:\s*\((
?:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\
x0D]))|)+)*\s*\)\s*))+)*\s*\)\s*)+|\s+)*\[(?:\s*(?-xism:(?-x
ism:[^\[\]\\])|(?-xism:\\(?-xism:[^\x0A\x0D])))+)*\s*\](?-xi
sm:(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xism:
\\(?-xism:[^\x0A\x0D]))|(?-xism:\s*\((?:\s*(?-xism:(?-xism:(
?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|)+)*\s*\)\s*))+
)*\s*\)\s*)+|\s+)*)))>(?-xism:(?-xism:\s*\((?:\s*(?-xism:(?-
xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|(?-xism:\
s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[^
\x0A\x0D]))|)+)*\s*\)\s*))+)*\s*\)\s*)+|\s+)*))|(?-xism:(?-x
ism:(?-xism:(?-xism:(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^
()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|(?-xism:\s*\((?:\s*
(?-xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D])
)|)+)*\s*\)\s*))+)*\s*\)\s*)+|\s+)*(?-xism:[^\x00-\x1F\x7F()
<>\[\]:;@\,.<DQ>\s]+(?:\.[^\x00-\x1F\x7F()<>\[\]:;@\,.<DQ>\s
]+)*)(?-xism:(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+)
)|(?-xism:\\(?-xism:[^\x0A\x0D]))|(?-xism:\s*\((?:\s*(?-xism
:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|)+)*\
s*\)\s*))+)*\s*\)\s*)+|\s+)*)|(?-xism:(?-xism:(?-xism:\s*\((
?:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\
x0D]))|(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-x
ism:\\(?-xism:[^\x0A\x0D]))|)+)*\s*\)\s*))+)*\s*\)\s*)+|\s+)
*<DQ>(?-xism:(?-xism:[^\\<DQ>])|(?-xism:\\(?-xism:[^\x0A\x0D
])))+<DQ>(?-xism:(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\
\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|(?-xism:\s*\((?:\s*(?-
xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|)
+)*\s*\)\s*))+)*\s*\)\s*)+|\s+)*))\@(?-xism:(?-xism:(?-xism:
(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(
?-xism:[^\x0A\x0D]))|(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[
^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|)+)*\s*\)\s*))+)*\
s*\)\s*)+|\s+)*(?-xism:[^\x00-\x1F\x7F()<>\[\]:;@\,.<DQ>\s]+
(?:\.[^\x00-\x1F\x7F()<>\[\]:;@\,.<DQ>\s]+)*)(?-xism:(?-xism
:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:
[^\x0A\x0D]))|(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+
))|(?-xism:\\(?-xism:[^\x0A\x0D]))|)+)*\s*\)\s*))+)*\s*\)\s*
)+|\s+)*)|(?-xism:(?-xism:(?-xism:\s*\((?:\s*(?-xism:(?-xism
:(?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|(?-xism:\s*\(
(?:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A
\x0D]))|)+)*\s*\)\s*))+)*\s*\)\s*)+|\s+)*\[(?:\s*(?-xism:(?-
xism:[^\[\]\\])|(?-xism:\\(?-xism:[^\x0A\x0D])))+)*\s*\](?-x
ism:(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xism
:\\(?-xism:[^\x0A\x0D]))|(?-xism:\s*\((?:\s*(?-xism:(?-xism:
(?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|)+)*\s*\)\s*))
+)*\s*\)\s*)+|\s+)*))))(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?
>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0D]))|(?-xism:\s*\((?:
\s*(?-xism:(?-xism:(?>[^()\\]+))|(?-xism:\\(?-xism:[^\x0A\x0
D]))|)+)*\s*\)\s*))+)*\s*\)\s*)*)"
  .Replace("<DQ>", "\"")
  .Replace("\t", "")
  .Replace(" ", "")
  .Replace("\r", "")
  .Replace("\n", "");

private static Regex mailbox =
  new Regex(gibberish, RegexOptions.ExplicitCapture); 

12

Згідно з офіційним стандартом RFC 2822, дійсною є регулярна вивірка електронної пошти

(?:[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])?|\[(?:(?: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-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])

якщо ви хочете використовувати його на Java, це дійсно дуже просто

import java.util.regex.*;

class regexSample 
{
   public static void main(String args[]) 
   {
      //Input the string for validation
      String email = "xyz@hotmail.com";

      //Set the email pattern string
      Pattern p = Pattern.compile(" (?:[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])?|\\[(?:(?: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-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21-\\x5a\\x53-\\x7f]|\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])+)\\]");

      //Match the given string with the pattern
      Matcher m = p.matcher(email);

      //check whether match is found 
      boolean matchFound = m.matches();

      if (matchFound)
        System.out.println("Valid Email Id.");
      else
        System.out.println("Invalid Email Id.");
   }
}

1
Ваш регекс не містить першого великого письма, наприклад Leonardo.davinci@gmail.com, що може дратувати деяких користувачів. Використовуйте це замість цього:(?:[A-Za-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[A-Za-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])?|\[(?:(?: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-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])
Kebab Krabby

@KebabKrabby Спасибі, будь ласка, відредагуйте відповідь, я прийму зміни.
AZ_

Якщо я додам цю зміну до своєї відповіді, вона більше не буде RFC 2822, тому я не знаю, чи правильно це.
Kebab Krabby

11

Ось PHP, який я використовую. Я вибрав це рішення в дусі "помилкові позитиви є кращими, ніж хибні негативи", як заявив інший коментатор тут. І щодо того, щоб тримати час реакції та завантажувати сервер вниз ... насправді не потрібно витрачати серверні ресурси на регулярний вираз, коли це усуне найпростішу помилку користувача. Ви завжди можете продовжити це, надіславши тестовий лист, якщо хочете.

function validateEmail($email) {
  return (bool) stripos($email,'@');
}

1
a) "Ресурси серверних відходів" нескінченно малі, але якщо ви настільки схильні, ви можете зробити це клієнтом із JS b) Що вам потрібно надіслати реєстраційну пошту, і користувач входить до мене @ forgotthedotcom? Ваше "рішення" виходить з ладу, і ви втрачаєте користувача.
Johnjohn

а) Покладатися на перевірку JS, яке не вдалося б після відключення JavaScript, не виглядає як найкраща ідея (просто btw)
auco

11

Стандарт RFC 5322:

Дозволяє локальній частині крапки-атома, локальній частині з цитованим рядком, застарілій (змішаний точка-атом і рядок з цитатами) локальній частині, доменного доменного імені, (адреса, що відображає IPv4, IPv6 і IPv4), буквальний домен домену, та (вкладені) CFWS.

'/^(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){255,})(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){65,}@)((?>(?>(?>((?>(?>(?>\x0D\x0A)?[\t ])+|(?>[\t ]*\x0D\x0A)?[\t ]+)?)(\((?>(?2)(?>[\x01-\x08\x0B\x0C\x0E-\'*-\[\]-\x7F]|\\\[\x00-\x7F]|(?3)))*(?2)\)))+(?2))|(?2))?)([!#-\'*+\/-9=?^-~-]+|"(?>(?2)(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\x7F]))*(?2)")(?>(?1)\.(?1)(?4))*(?1)@(?!(?1)[a-z0-9-]{64,})(?1)(?>([a-z0-9](?>[a-z0-9-]*[a-z0-9])?)(?>(?1)\.(?!(?1)[a-z0-9-]{64,})(?1)(?5)){0,126}|\[(?:(?>IPv6:(?>([a-f0-9]{1,4})(?>:(?6)){7}|(?!(?:.*[a-f0-9][:\]]){8,})((?6)(?>:(?6)){0,6})?::(?7)?))|(?>(?>IPv6:(?>(?6)(?>:(?6)){5}:|(?!(?:.*[a-f0-9]:){6,})(?8)?::(?>((?6)(?>:(?6)){0,4}):)?))?(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?>\.(?9)){3}))\])(?1)$/isD'

RFC 5321 стандарт:

Дозволяє локальній частині крапки-атома, локальній частині з цитованим рядком, доменного доменного імені та (IPv4, IPv6 та IPv4-адресована IPv6 адреса), буквальному домені домену.

'/^(?!(?>"?(?>\\\[ -~]|[^"])"?){255,})(?!"?(?>\\\[ -~]|[^"]){65,}"?@)(?>([!#-\'*+\/-9=?^-~-]+)(?>\.(?1))*|"(?>[ !#-\[\]-~]|\\\[ -~])*")@(?!.*[^.]{64,})(?>([a-z0-9](?>[a-z0-9-]*[a-z0-9])?)(?>\.(?2)){0,126}|\[(?:(?>IPv6:(?>([a-f0-9]{1,4})(?>:(?3)){7}|(?!(?:.*[a-f0-9][:\]]){8,})((?3)(?>:(?3)){0,6})?::(?4)?))|(?>(?>IPv6:(?>(?3)(?>:(?3)){5}:|(?!(?:.*[a-f0-9]:){6,})(?5)?::(?>((?3)(?>:(?3)){0,4}):)?))?(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?>\.(?6)){3}))\])$/iD'

Основні:

Дозволяє локальній частині доменного і доменного імені домену (потрібні принаймні дві мітки доменних імен з TLD, обмеженими 2-6 алфавітними символами).

"/^(?!.{255,})(?!.{65,}@)([!#-'*+\/-9=?^-~-]+)(?>\.(?1))*@(?!.*[^.]{64,})(?>[a-z0-9](?>[a-z0-9-]*[a-z0-9])?\.){1,126}[a-z]{2,6}$/iD"

Що за чортова мова, що в ?? Я бачу /Dпрапор, і ви його процитували за допомогою одинарних лапок, але ви також використовували косої риски для розмежування шаблону? Це не Perl, і це не може бути PCRE. Тому це PHP? Я вважаю, що це єдині три, які допускають подібні рекурсії (?1).
tchrist

Це в PHP, де використовується PCRE. Штрихи використовуються лише для розмежування спеціальних символів, таких як дужки, квадратні дужки, і, звичайно, косої риски та одинарні лапки. Прапор / D, якщо ви цього не знали, повинен запобігти додаванню нової рядка в кінець рядка, що дозволено інакше.
MichaelRushton

9

Дивно, що ви "не можете" дозволити 4 символи TLD. Ви забороняєте людям використовувати .info та .name , а обмеження довжини зупиняти .travel та .museum , але так, вони рідше, ніж два символи TLD та 3 символи TLD.

Ви також повинні дозволити великі літери. Системи електронної пошти нормалізують локальну та доменну частину.

Для вашого регексу доменної частини доменне ім’я не може починатися з "-" і не може закінчуватися з "-". Тире може залишатися лише посередині.

Якщо ви використовували бібліотеку PEAR, ознайомтеся з їх функцією пошти (забули точну назву / бібліотеку). Ви можете перевірити електронну адресу, зателефонувавши за однією функцією, і вона перевіряє адресу електронної пошти відповідно до визначення в RFC822.


2
@Joseph Yee: Не RFC 822 трохи датований?
tchrist

8
public bool ValidateEmail(string sEmail)
{
    if (sEmail == null)
    {
        return false;
    }

    int nFirstAT = sEmail.IndexOf('@');
    int nLastAT = sEmail.LastIndexOf('@');

    if ((nFirstAT > 0) && (nLastAT == nFirstAT) && (nFirstAT < (sEmail.Length - 1)))
    {
        return (Regex.IsMatch(sEmail, @"^[a-z|0-9|A-Z]*([_][a-z|0-9|A-Z]+)*([.][a-z|0-9|A-Z]+)*([.][a-z|0-9|A-Z]+)*(([_][a-z|0-9|A-Z]+)*)?@[a-z][a-z|0-9|A-Z]*\.([a-z][a-z|0-9|A-Z]*(\.[a-z][a-z|0-9|A-Z]*)?)$"));
    }
    else
    {
        return false;
    }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.