Bagaimana cara memvalidasi alamat email menggunakan ekspresi reguler?

3313

Selama bertahun-tahun saya perlahan mengembangkan ekspresi reguler yang memvalidasi alamat email PALING dengan benar, dengan asumsi mereka tidak menggunakan alamat IP sebagai bagian server.

Saya menggunakannya di beberapa program PHP, dan itu berfungsi sebagian besar waktu. Namun, dari waktu ke waktu saya dihubungi oleh seseorang yang mengalami masalah dengan situs yang menggunakannya, dan saya akhirnya harus melakukan beberapa penyesuaian (baru-baru ini saya menyadari bahwa saya tidak mengizinkan TLD 4-karakter).

Apa ekspresi reguler terbaik yang Anda miliki atau lihat untuk memvalidasi email?

Saya telah melihat beberapa solusi yang menggunakan fungsi yang menggunakan beberapa ekspresi yang lebih pendek, tetapi saya lebih suka memiliki satu ekspresi kompleks panjang dalam fungsi sederhana daripada beberapa ekspresi pendek dalam fungsi yang lebih kompleks.

pelamar
sumber
23
Agak relevan XKCD
gerrit
5
Regex yang dapat memvalidasi bahwa IDNA diformat dengan benar tidak cocok di stackexchange. (aturan kanonikalisasi makan sangat berliku-liku dan sangat tidak cocok untuk pemrosesan regex)
Jasen
4
Mengapa Anda tidak melakukan ini: Bisakah membahayakan memvalidasi alamat email dengan regex?
klutt
Regex dapat berubah- ubah karena dalam beberapa kasus, con email dapat berisi spasi, dan di waktu lain, itu tidak dapat berisi spasi.
Ṃųỻịgǻňạcểơửṩ

Jawaban:

2440

The sepenuhnya RFC 822 regex compliant tidak efisien dan tidak jelas karena panjangnya. Untungnya, RFC 822 digantikan dua kali dan spesifikasi saat ini untuk alamat email adalah RFC 5322 . RFC 5322 mengarah ke regex yang dapat dipahami jika dipelajari selama beberapa menit dan cukup efisien untuk penggunaan aktual.

Satu regex compliant RFC 5322 dapat ditemukan di bagian atas halaman di http://emailregex.com/ tetapi menggunakan pola alamat IP yang mengambang di internet dengan bug yang memungkinkan 00untuk setiap nilai desimal byte yang tidak ditandatangani dalam suatu alamat dot-delimited, yang ilegal. Sisanya tampaknya konsisten dengan tata bahasa RFC 5322 dan melewati beberapa tes menggunakan grep -Po, termasuk nama domain kasus, alamat IP, yang buruk, dan nama akun dengan dan tanpa tanda kutip.

Mengoreksi 00bug dalam pola IP, kami memperoleh regex yang berfungsi dan cukup cepat. (Gosok versi yang diberikan, bukan penurunan harga, untuk kode aktual.)

(?: [a-z0-9! # $% & '* + / =? ^ _ `{|} ~ - + + (?: \. [a-z0-9! # $% &' * + / =? ^ _ `{|} ~ -] +) * |" (?: [\ x01- \ x08 \ x0b \ x0c \ x0f \ 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 \ x0f \ x1f \ x21f \ x21a \ x5a \ x53- \ x7f] | \\ [\ x01- \ x09 \ x0b \ x0c \ x0e- \ x7f]) +) \])

atau:

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

Berikut ini adalah diagram dari mesin negara yang terbatas untuk regexp di atas yang lebih jelas dari regexp sendiri masukkan deskripsi gambar di sini

Pola yang lebih canggih dalam Perl dan PCRE (pustaka regex yang digunakan misalnya dalam PHP) dapat dengan benar mengurai RFC 5322 tanpa hambatan . Python dan C # dapat melakukannya juga, tetapi mereka menggunakan sintaks yang berbeda dari dua yang pertama. Namun, jika Anda terpaksa menggunakan salah satu dari banyak bahasa pencocokan pola yang kurang kuat, maka yang terbaik adalah menggunakan parser nyata.

Penting juga untuk dipahami bahwa memvalidasinya per RFC sama sekali tidak memberi tahu Anda apakah alamat itu benar-benar ada di domain yang disediakan, atau apakah orang yang memasukkan alamat itu adalah pemiliknya yang sebenarnya. Orang-orang mendaftar orang lain ke milis dengan cara ini sepanjang waktu. Memperbaiki yang memerlukan jenis validasi yang lebih menarik yang melibatkan pengiriman pesan yang menyertakan alamat konfirmasi yang dimaksudkan untuk dimasukkan pada halaman web yang sama dengan alamat.

Token konfirmasi adalah satu-satunya cara untuk mengetahui Anda mendapatkan alamat orang yang memasukkannya. Inilah sebabnya sebagian besar milis sekarang menggunakan mekanisme itu untuk mengonfirmasi pendaftaran. Lagipula, siapa pun dapat meletakkannya [email protected], dan itu bahkan akan diurai sebagai legal, tetapi tidak mungkin menjadi orang di ujung lainnya.

Untuk PHP, Anda sebaiknya tidak menggunakan pola yang diberikan dalam Validasi Alamat E-Mail dengan PHP, Cara yang Benar dari mana saya mengutip:

Ada beberapa bahaya bahwa penggunaan umum dan pengkodean ceroboh yang meluas akan menetapkan standar de facto untuk alamat email yang lebih ketat daripada standar formal yang tercatat.

Itu tidak lebih baik dari semua pola non-RFC lainnya. Bahkan tidak cukup cerdas untuk menangani bahkan RFC 822 , apalagi RFC 5322. Yang satu ini , bagaimanapun, adalah.

Jika Anda ingin menjadi mewah dan gagah, menerapkan mesin negara lengkap . Ekspresi reguler hanya dapat bertindak sebagai filter yang belum sempurna. Masalah dengan ekspresi reguler adalah bahwa memberi tahu seseorang bahwa alamat email yang benar-benar valid tidak valid (false positive) karena ekspresi reguler Anda tidak dapat menanganinya itu tidak sopan dan tidak sopan dari sudut pandang pengguna. Mesin negara untuk tujuan tersebut dapat memvalidasi dan bahkan memperbaiki alamat email yang dinyatakan tidak valid karena membongkar alamat email sesuai dengan masing-masing RFC. Ini memungkinkan untuk pengalaman yang berpotensi lebih menyenangkan, seperti

Alamat email yang ditentukan 'myemail @ address, com' tidak valid. Apakah maksud Anda '[email protected]'?

Lihat juga Memvalidasi Alamat Email , termasuk komentar. Atau Membandingkan Alamat E-mail yang Memvalidasi Ekspresi Reguler .

Visualisasi ekspresi reguler

Demo Debuggex

bortzmeyer
sumber
180
Anda berkata, "Tidak ada ekspresi reguler yang bagus." Apakah ini umum atau khusus untuk validasi alamat email?
Tomalak
37
@ Tomalak: hanya untuk alamat email. Seperti yang dikatakan bortzmeyer, RFC sangat rumit
Luk
37
Artikel jurnal linux yang Anda sebutkan secara faktual salah dalam beberapa hal. Secara khusus Lovell jelas belum membaca errata ke RFC3696 dan mengulangi beberapa kesalahan dalam versi RFC yang dipublikasikan. Lebih lanjut di sini: dominicsayers.com/isemail
Dominic Sayers
9
Jeff Atwood memiliki regex yang indah di posting blog ini untuk memvalidasi semua alamat email yang valid: codinghorror.com/blog/2005/02/regex-use-vs-regex-abuse.html
CMircea
5
Perhatikan bahwa spesifikasi HTML5 saat ini mencakup regex dan ABNF untuk validasi input tipe email yang sengaja lebih ketat daripada RFC asli.
Sinkronisasi
747

Anda tidak boleh menggunakan ekspresi reguler untuk memvalidasi alamat email.

Sebagai gantinya, gunakan kelas MailAddress , seperti ini:

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

The MailAddresskelas menggunakan parser BNF untuk memvalidasi alamat sesuai penuh dengan RFC822.

Jika Anda berencana untuk menggunakan MailAddressuntuk memvalidasi alamat email, ketahuilah bahwa pendekatan ini juga menerima bagian nama tampilan dari alamat email, dan itu mungkin tidak persis seperti apa yang ingin Anda capai. Misalnya, ia menerima string ini sebagai alamat email yang valid:

Dalam beberapa kasus ini, hanya bagian terakhir dari string yang diuraikan sebagai alamat; sisanya sebelum itu adalah nama tampilan. Untuk mendapatkan alamat email biasa tanpa nama tampilan, Anda dapat memeriksa alamat yang dinormalisasi terhadap string asli Anda.

bool isValid = false;

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

Selain itu, alamat yang memiliki titik di akhir, seperti user@company.juga diterima oleh MailAddress.

Jika Anda benar-benar ingin menggunakan regex, ini dia :

(?: (?: \ 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 *)
Slaks
sumber
26
Anda akan menemukan bahwa kelas MailAddress di .NET 4.0 jauh lebih baik dalam memvalidasi alamat email daripada di versi sebelumnya. Saya membuat beberapa perbaikan signifikan untuk itu.
Jeff Tucker
7
Saya pikir itu semacam ... tidak bekerja ... untuk id lebih sederhana. a @ b tidak memvalidasi. [email protected] hanya cocok hingga ar @ b, .com tidak cocok. Namun, sesuatu seperti "Aku adalah aku" @ [10.10.10.10] tidak berfungsi! :)
Raze
5
Berhati-hatilah bahwa validator regex yang mematuhi RFC ini akan membiarkan banyak alamat email yang Anda mungkin tidak ingin terima seperti "a <body / onload = lansiran (' lol.com?'+document.cookies ) @aa> "yang merupakan alamat email yang valid di Email perl: :: Valid (yang menggunakan regex besar itu), dan dapat dieksploitasi untuk XSS rt.cpan.org/Public/Bug/Display.html?id=75650
Matthew Lock
9
@ MatthewLock: Itu tidak lebih buruk dari [email protected]. Anda tidak boleh mengandalkan validasi email untuk mencegah XSS.
SLaks
10
@ MatthewLock: Tidak. Anda harus keluar dari query SQL (atau, lebih baik lagi, gunakan parameter). Sanitasi bukan pertahanan yang tepat.
SLaks
536

Pertanyaan ini banyak ditanyakan, tetapi saya pikir Anda harus mundur dan bertanya pada diri sendiri mengapa Anda ingin memvalidasi alamat email secara sintaksis? Apa manfaatnya sebenarnya?

  • Itu tidak akan menangkap kesalahan ketik umum.
  • Itu tidak mencegah orang memasukkan alamat email yang tidak benar atau dibuat-buat, atau memasukkan alamat orang lain.

Jika Anda ingin memvalidasi bahwa email itu benar, Anda tidak punya pilihan selain mengirim email konfirmasi dan meminta pengguna membalasnya. Dalam banyak kasus Anda tetap harus mengirim surat konfirmasi untuk alasan keamanan atau karena alasan etis (jadi Anda tidak bisa misalnya mendaftar seseorang ke layanan yang bertentangan dengan keinginan mereka).

JacquesB
sumber
92
Mungkin perlu memeriksa bahwa mereka memasukkan sesuatu @ sesuatu ke bidang dalam validasi sisi klien hanya untuk menangkap kesalahan sederhana - tetapi secara umum Anda benar.
Martin Beckett
8
Martin, saya memberi Anda +1, hanya untuk kemudian membaca bahwa foobar @ dk adalah email yang valid. Itu tidak akan cantik, tetapi jika Anda ingin menjadi RFC yang patuh DAN menggunakan akal sehat, Anda harus mendeteksi kasus seperti ini dan meminta pengguna untuk mengonfirmasi bahwa itu benar.
philfreo
106
@olavk: jika seseorang memasukkan salah ketik (misalnya:) me@hotmail, mereka jelas tidak akan mendapatkan email konfirmasi Anda, lalu di mana mereka? Mereka tidak ada di situs Anda lagi dan mereka bertanya-tanya mengapa mereka tidak dapat mendaftar. Sebenarnya tidak, mereka tidak - mereka benar-benar lupa tentang Anda. Namun, jika Anda bisa melakukan pemeriksaan kewarasan dasar dengan regex saat mereka masih bersama Anda, maka mereka dapat langsung menangkap kesalahan itu dan Anda memiliki pengguna yang bahagia.
nickf
5
@ JacquesB: Anda membuat poin yang bagus. Hanya karena ia lolos dengan cepat per RFC tidak berarti alamat pengguna itu benar-benar. Kalau tidak, semua [email protected]alamat itu menunjukkan komandan tertinggi netbusy. :)
tchrist
39
Tidak harus hitam atau putih. Jika email terlihat salah, beri tahu pengguna itu. Jika pengguna masih ingin melanjutkan, biarkan dia. Jangan memaksa pengguna untuk menyesuaikan diri dengan regex Anda, melainkan, gunakan regex sebagai alat untuk membantu pengguna mengetahui bahwa mungkin ada kesalahan.
ninjaneer
354

Itu semua tergantung pada seberapa akurat yang Anda inginkan. Untuk tujuan saya, di mana saya hanya mencoba untuk mencegah hal-hal seperti bob @ aol.com(spasi di email) atau steve(tidak ada domain sama sekali) atau mary@aolcom(tidak ada periode sebelum .com), saya menggunakan

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

Tentu, ini akan cocok dengan hal-hal yang bukan alamat email yang valid, tetapi masalah mendapatkan kesalahan sederhana yang umum.

Ada sejumlah perubahan yang dapat dilakukan pada regex itu (dan beberapa ada di komentar untuk jawaban ini), tetapi sederhana, dan mudah dimengerti, dan merupakan upaya pertama yang bagus.

Andy Lester
sumber
6
Itu tidak cocok dengan foobar @ dk yang merupakan alamat email yang valid dan berfungsi (walaupun mungkin sebagian besar server email tidak akan menerimanya atau akan menambahkan something.com.)
bortzmeyer
3
Ya, tentu saja. Saya sarankan Anda mencobanya sendiri. $ perl -le'print q{[email protected]} = ~ /^\S+@#S+\.\S+$/? q {Y}: q {N} '
Andy Lester
7
@ Richard: .termasuk dalam \S.
David Thornley
43
JJJ: Ya, itu akan cocok dengan banyak omong kosong. Ini akan cocok dengan & $ * # $ (@ $ 0 (%)) $ #.) & *) (* $ Juga. Bagi saya, saya lebih peduli dengan menangkap kesalahan ketik jari aneh seperti mary@aolcomdaripada saya benar-benar sampah YMMV
Andy Lester
5
Hanya untuk mengontrol @tanda - tanda: /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/ jsfiddle.net/b9chris/mXB96
Chris Moschini
338

Itu tergantung pada apa yang Anda maksud dengan yang terbaik: Jika Anda berbicara tentang menangkap setiap alamat email yang valid, gunakan yang berikut ini:

(?:(?:\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 ) Jika Anda mencari sesuatu yang lebih sederhana tetapi itu akan menangkap sebagian besar alamat email yang valid coba sesuatu seperti:

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

EDIT: Dari tautan:

Ekspresi reguler ini hanya akan memvalidasi alamat yang komentarnya dihapus dan diganti dengan spasi putih (ini dilakukan oleh modul).

Orang Baik
sumber
10
Itu tidak cocok dengan semua alamat, beberapa harus diubah terlebih dahulu. Dari tautan: "Ekspresi reguler ini hanya akan memvalidasi alamat yang komentarnya dihapus dan diganti dengan spasi putih (ini dilakukan oleh modul)."
Chas. Owens
47
Bisakah Anda memberi saya contoh beberapa email addressyang salah melewati yang kedua, tetapi tertangkap oleh regex yang lebih lama?
Lazer
4
Meskipun saya pernah menyukainya, itu adalah validator RFC 822, bukan RFC 5322 .
tchrist
24
@Lazer in..valid @ example.com akan menjadi contoh sederhana. Anda tidak diizinkan memiliki dua titik tanpa kutip berturut-turut di bagian lokal.
Randal Schwartz
5
@Mikhail perl tetapi Anda seharusnya tidak benar-benar menggunakannya.
Orang Baik
287

[DIPERBARUI] Saya telah mengumpulkan semua yang saya ketahui tentang validasi alamat email di sini: http://isemail.info , yang sekarang tidak hanya memvalidasi tetapi juga mendiagnosis masalah dengan alamat email. Saya setuju dengan banyak komentar di sini bahwa validasi hanya bagian dari jawabannya; lihat esai saya di http://isemail.info/about .

is_email () tetap, sejauh yang saya tahu, satu-satunya validator yang akan memberi tahu Anda secara pasti apakah string yang diberikan adalah alamat email yang valid atau tidak. Saya sudah mengunggah versi baru di http://isemail.info/

Saya mengumpulkan test case dari Cal Henderson, Dave Child, Phil Haack, Doug Lovell, RFC5322 dan RFC 3696. 275 alamat tes semuanya. Saya menjalankan semua tes ini terhadap semua validator gratis yang dapat saya temukan.

Saya akan mencoba menjaga halaman ini tetap mutakhir karena orang-orang meningkatkan validator mereka. Terima kasih kepada Cal, Michael, Dave, Paul dan Phil atas bantuan dan kerja sama mereka dalam menyusun tes-tes ini dan kritik yang membangun terhadap validator saya sendiri .

Orang-orang harus menyadari errata terhadap RFC 3696 pada khususnya. Tiga dari contoh kanonik sebenarnya adalah alamat yang tidak valid. Dan panjang maksimal alamat adalah 254 atau 256 karakter, bukan 320.

Dominic Sayers
sumber
Validator ini juga tampaknya benar. [... waktu berlalu ...] Hm, sepertinya itu hanya RFC 5322, bukan 3693 atau errata karenanya.
tchrist
1
Sangat bagus. Di sini kita tidak hanya mendapatkan esai yang bagus, kita mendapatkan tester validasi serta pustaka untuk diunduh. Jawaban bagus!
bgmCoder
Validator Anda tidak mendukung punycode (RFC 3492). name@öäü.at bisa menjadi alamat yang valid. (Diterjemahkan ke [email protected])
Josef mengatakan Reinstate Monica
Hai @ Josef. Anda harus mencoba memvalidasi [email protected]karena kode ini tentang validasi, bukan interpretasi. Jika Anda ingin menambahkan penerjemah punycode, maka saya senang menerima permintaan tarik di github.com/dominicsayers/isemail
Dominic Sayers
266

Per spesifikasi 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])?)*$

Konteks:

Sebuah alamat e-mail yang valid adalah string yang cocok dengan produksi ABNF [...].

Catatan: Persyaratan ini adalah pelanggaran yang disengaja dari RFC 5322 , yang mendefinisikan sintaks untuk alamat e-mail yang bersamaan terlalu ketat (sebelum “@” karakter), terlalu samar (setelah “@” karakter), dan terlalu longgar ( memungkinkan komentar, karakter spasi putih, dan string kutipan dalam perilaku yang tidak dikenal oleh sebagian besar pengguna) dapat digunakan secara praktis di sini.

Ekspresi reguler yang kompatibel dengan JavaScript dan Perl adalah implementasi dari definisi di atas.

/^[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])?)*$/

Rory O'Kane
sumber
12
Ini menarik. Ini pelanggaran RFC, tapi disengaja dan itu membuat sesne. Contoh dunia nyata: gmail mengabaikan titik-titik di bagian sebelum @, jadi jika email Anda adalah [email protected], Anda dapat mengirim email untuk menguji. @ Gmail.com atau test .... @ gmail.com, kedua alamat tersebut adalah tidak valid menurut RFC, tetapi valid di dunia nyata.
valentinas
Saya pikir bagian terakhir harus '+' bukan '*': ^ [a-zA-Z0-9.! # $% & '* + / =? ^ _ `{|} ~ -] + @ [a- zA-Z0-9 -] + (?: \. [a-zA-Z0-9 -] +) + $
mmmmmm
7
@mmmmmm john.doe@localhostbenar. Yang pasti, dalam aplikasi dunia nyata (yaitu komunitas), saya ingin saran Anda untuk mengganti * dengan +
rabudde
3
@valentinas Sebenarnya, RFC tidak menghalangi bagian lokal ini, tetapi mereka harus dikutip. "test...."@gmail.comsecara valid sesuai dengan RFC dan secara semantik setara dengan [email protected].
Rinke
Saya mendapatkan kesalahan saat mencoba mengirim email menggunakan python melalui relay perusahaan saya jika saya mencoba mengirim ke alamat dengan. @ Atau .. @. Sebenarnya itu juga halnya dengan _ @. Saya lebih suka menghapusnya sebelum mengirim daripada percaya bahwa penerima akan melakukannya.
ndvo
201

Mudah di Perl 5.10 atau lebih baru:

/(?(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
Abigail
sumber
20
Senang
4
Saya pikir hanya sebagian dari addrspecbagian yang benar-benar relevan dengan pertanyaan. Menerima lebih dari itu dan meneruskannya meskipun beberapa bagian lain dari sistem yang tidak siap menerima alamat RFC5822 lengkap seperti menembak adalah kaki Anda sendiri.
dolmen
3
Hebat (+1) tetapi secara teknis itu bukan regex tentu saja ... (yang tidak mungkin karena tata bahasa tidak teratur).
Rinke
10
regex berhenti teratur beberapa waktu lalu. Ini adalah Perl 'regex' yang valid!
rjh
4
Aku mengatur tes untuk regex ini pada IDEone: ideone.com/2XFecH Namun, itu tidak adil "sempurna." Adakah yang mau berpadu? Apakah saya melewatkan sesuatu?
Mike
159

saya menggunakan

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

Yang digunakan di ASP.NET oleh RegularExpressionValidator.

Per Hornshøj-Schierbeck
sumber
28
Boo! Alamat saya (keliru) [email protected]ditolak.
Phrogz
3
Menurut halaman ini data.iana.org/TLD/tlds-alpha-by-domain.txt tidak ada domain dengan hanya satu karakter di tingkat atas mis. " Something.c ", "something.a", ini adalah versi yang mendukung setidaknya 2 karakter: "something.pl", "something.us":^\\w+([-+.']\\w+)*@\\w+([-.]\\w+)*\\.\\w{2,}([-.]\\w+)*$
Tomasz Szulc
4
@Wayne Whitty. Anda telah menemukan masalah utama apakah akan memenuhi sebagian besar alamat, atau SEMUA, termasuk yang tidak akan digunakan siapa pun, kecuali untuk menguji validasi email.
Patanjali
@TomaszSzulc back slash tambahan dalam jawaban Anda membingungkan, saya baru saja memperbaikinya dan 2 chars dukungan nama domain berfungsi, ^ \ w + ([- +. '] \ W +) * @ \ w + ([-.] \ W +) * \. \ w {2,} ([-.] \ w +) * $
Aqib Mumtaz
2
ini gagal [email protected]yang sebenarnya valid (pelanggan kami memiliki alamat yang sama) `
Simon_Weaver
142

Tidak tahu yang terbaik, tapi yang ini paling tidak benar, selama alamatnya dihapus dan diganti dengan spasi putih.

Serius. Anda harus menggunakan perpustakaan yang sudah ditulis untuk memvalidasi email. Cara terbaik adalah mengirim email verifikasi ke alamat itu.

Christian Vest Hansen
sumber
2
Sejauh yang saya tahu, beberapa perpustakaan juga salah. Samar-samar saya ingat bahwa PHP PEAR memiliki bug seperti itu.
bortzmeyer
Halaman itu juga memiliki penafian di bagian bawah tentang beberapa hal dari spec. bahwa regexp tidak mendukung.
Chris Vest
7
Itu spesifikasi RFC 822, bukan spesifikasi RFC 5322 .
tchrist
12
Pada akhirnya, dia benar karena satu-satunya cara untuk benar-benar memvalidasi alamat email adalah dengan mengirim email ke sana dan menunggu balasan.
Blazemonger
109

Alamat email yang ingin saya validasi akan digunakan oleh aplikasi web ASP.NET menggunakan namespace System.Net.Mail untuk mengirim email ke daftar orang. Jadi, daripada menggunakan beberapa ekspresi reguler yang sangat kompleks, saya hanya mencoba membuat instance MailAddress dari alamat. Konstruktor MailAddress akan mengeluarkan pengecualian jika alamat tidak dibentuk dengan benar. Dengan cara ini, saya tahu saya setidaknya bisa mengeluarkan email dari pintu. Tentu saja ini adalah validasi sisi server tetapi setidaknya Anda memerlukannya.

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;
    }
}
davcar
sumber
3
Poin yang bagus. Bahkan jika validasi server ini menolak beberapa alamat yang valid maka itu tidak menjadi masalah karena Anda tidak akan dapat mengirim ke alamat ini menggunakan teknologi server khusus ini. Atau Anda dapat mencoba melakukan hal yang sama menggunakan pustaka email pihak ketiga mana pun yang Anda gunakan alih-alih alat default.
Pengguna
Saya sangat suka bagaimana ini memanfaatkan .Net framework code - tidak masuk akal dalam menciptakan kembali roda. Ini luar biasa. Sederhana, bersih, dan meyakinkan Anda benar-benar dapat mengirim email. Kerja bagus.
Cory House
... ya dan bagi mereka yang tertarik tentang bagaimana memvalidasi lihat kode di Reflektor - ada cukup banyak - dan itu bukan ekspresi reguler!
Tom Carter
2
Hanya sebuah catatan: kelas MailAddress tidak cocok dengan RFC5322, jika Anda hanya ingin menggunakannya untuk validasi (dan tidak mengirim juga, dalam hal ini ini adalah poin diperdebatkan seperti yang disebutkan di atas). Lihat: stackoverflow.com/questions/6023589/…
porges
Hanya masalah kecil: jika Anda ingin membuat kode validator sisi server Anda lebih dapat digunakan kembali (baik dalam kasus ini atau secara umum), saya sarankan untuk menggunakan args.Valuealih-alih merujuk pada bidang seperti txtEmail.Texthard-coded. Yang terakhir akan mengikat validator Anda ke instance kontrol tunggal, yang mungkin OK, selama Anda memiliki bidang email tunggal, tetapi tidak disarankan sebaliknya.
pholpar
109

Jawaban cepat

Gunakan regex berikut untuk validasi input:

([-!#-'*+/-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])?)+

Alamat yang cocok dengan regex ini:

  • memiliki bagian lokal (yaitu bagian sebelum tanda-@) yang sepenuhnya sesuai dengan RFC 5321/5322,
  • memiliki bagian domain (yaitu bagian setelah tanda-@) yang merupakan nama host dengan setidaknya dua label, yang masing-masing memiliki paling banyak 63 karakter.

Kendala kedua adalah pembatasan pada RFC 5321/5322.

Jawaban yang rumit

Menggunakan ekspresi reguler yang mengenali alamat email dapat berguna dalam berbagai situasi: misalnya untuk memindai alamat email dalam dokumen, untuk memvalidasi input pengguna, atau sebagai batasan integritas pada repositori data.

Namun perlu dicatat bahwa jika Anda ingin mengetahui apakah alamat tersebut benar-benar merujuk ke kotak surat yang ada, tidak ada pengganti untuk mengirim pesan ke alamat tersebut. Jika Anda hanya ingin memeriksa apakah suatu alamat secara tata bahasa benar maka Anda dapat menggunakan ekspresi reguler, tetapi perhatikan bahwa itu ""@[]adalah alamat email yang benar secara tata bahasa yang tentu saja tidak merujuk ke kotak surat yang ada.

Sintaks alamat email telah didefinisikan dalam berbagai RFC , terutama RFC 822 dan RFC 5322 . RFC 822 harus dilihat sebagai standar "asli" dan RFC 5322 sebagai standar terbaru. Sintaks yang didefinisikan dalam RFC 822 adalah standar yang paling lunak dan selanjutnya telah membatasi sintaks lebih lanjut dan lebih jauh, di mana sistem atau layanan yang lebih baru harus mengenali sintaks yang usang, tetapi tidak pernah memproduksinya.

Dalam jawaban ini saya akan mengambil "alamat email" untuk berarti addr-specsebagaimana didefinisikan dalam RFC (yaitu [email protected], tetapi tidak "John Doe"<[email protected]>, tidak juga some-group:[email protected],[email protected];).

Ada satu masalah dengan menerjemahkan sintaks RFC ke dalam regex: sintaksinya tidak teratur! Ini karena mereka memungkinkan untuk komentar opsional di alamat email yang dapat disarangkan tanpa batas, sementara bersarang tanpa batas tidak dapat dijelaskan dengan ekspresi reguler. Untuk memindai atau memvalidasi alamat yang berisi komentar, Anda memerlukan parser atau ekspresi yang lebih kuat. (Perhatikan bahwa bahasa seperti Perl memiliki konstruksi untuk menggambarkan tata bahasa bebas konteks dengan cara seperti regex.) Dalam jawaban ini saya akan mengabaikan komentar dan hanya mempertimbangkan ekspresi reguler yang tepat.

RFC menentukan sintaksis untuk pesan email, bukan untuk alamat email. Alamat dapat muncul di berbagai bidang tajuk dan ini adalah tempat mereka ditentukan. Ketika mereka muncul di alamat bidang header mungkin berisi (antara token leksikal) spasi putih, komentar dan bahkan linebreak. Namun secara semantik ini tidak memiliki signifikansi. Dengan menghapus spasi putih ini, dll dari alamat, Anda mendapatkan representasi kanonik yang secara semantik setara . Dengan demikian, representasi kanonik first. last (comment) @ [3.5.7.9]adalah first.last@[3.5.7.9].

Sintaks yang berbeda harus digunakan untuk tujuan yang berbeda. Jika Anda ingin memindai alamat email dalam dokumen (mungkin sangat lama) mungkin ide yang baik untuk menggunakan sintaksis seperti yang didefinisikan dalam RFC 822. Di sisi lain, jika Anda ingin memvalidasi input pengguna Anda mungkin ingin menggunakan sintaksis sebagaimana didefinisikan dalam RFC 5322, mungkin hanya menerima representasi kanonik. Anda harus memutuskan sintaksis mana yang berlaku untuk kasus spesifik Anda.

Saya menggunakan ekspresi reguler POSIX "extended" dalam jawaban ini, dengan asumsi rangkaian karakter yang kompatibel ASCII.

RFC 822

Saya tiba di ekspresi reguler berikut. Saya mengundang semua orang untuk mencoba dan memecahkannya. Jika Anda menemukan kesalahan positif atau negatif palsu, kirimkan dalam komentar dan saya akan mencoba untuk memperbaiki ekspresi sesegera mungkin.

([^][()<>@,;:\\". \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)*]))*

Saya percaya ini sepenuhnya sesuai dengan RFC 822 termasuk errata . Itu hanya mengenali alamat email dalam bentuk kanonik mereka. Untuk regex yang mengenali spasi (melipat) lihat derivasi di bawah ini.

Derivasi menunjukkan bagaimana saya sampai pada ekspresi. Saya mencantumkan semua aturan tata bahasa yang relevan dari RFC persis seperti yang muncul, diikuti oleh regex yang sesuai. Di mana erratum telah diterbitkan, saya memberikan ekspresi terpisah untuk aturan tata bahasa yang diperbaiki (ditandai "erratum") dan menggunakan versi yang diperbarui sebagai subekspresi dalam ekspresi reguler berikutnya.

Sebagaimana dinyatakan dalam paragraf 3.1.4. RFC 822 spasi putih linier opsional dapat dimasukkan di antara token leksikal. Jika berlaku, saya telah memperluas ekspresi untuk mengakomodasi aturan ini dan menandai hasilnya dengan "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

Saya tiba di ekspresi reguler berikut. Saya mengundang semua orang untuk mencoba dan memecahkannya. Jika Anda menemukan kesalahan positif atau negatif palsu, kirimkan dalam komentar dan saya akan mencoba untuk memperbaiki ekspresi sesegera mungkin.

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

Saya percaya ini sepenuhnya sesuai dengan RFC 5322 termasuk errata . Itu hanya mengenali alamat email dalam bentuk kanonik mereka. Untuk regex yang mengenali spasi (melipat) lihat derivasi di bawah ini.

Derivasi menunjukkan bagaimana saya sampai pada ekspresi. Saya mencantumkan semua aturan tata bahasa yang relevan dari RFC persis seperti yang muncul, diikuti oleh regex yang sesuai. Untuk aturan yang menyertakan spasi putih yang tidak relevan (melipat), saya memberikan regex terpisah bertanda "(dinormalisasi)" yang tidak menerima spasi putih ini.

Saya mengabaikan semua aturan "obs-" dari RFC. Ini berarti bahwa regex hanya cocok dengan alamat email yang sepenuhnya sesuai dengan RFC 5322. Jika Anda harus mencocokkan alamat "lama" (seperti tata bahasa yang lebih longgar termasuk aturan "obs-"), Anda dapat menggunakan salah satu dari regex RFC 822 dari paragraf sebelumnya.

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^-~]*])

Perhatikan bahwa beberapa sumber (terutama w3c ) mengklaim bahwa RFC 5322 terlalu ketat pada bagian lokal (yaitu bagian sebelum tanda-@). Ini karena "..", "a..b" dan "a." yang tidak valid dot-atom, sementara mereka dapat digunakan sebagai nama kotak surat. RFC, bagaimanapun, tidak memungkinkan untuk bagian lokal seperti ini, kecuali bahwa mereka telah dikutip. Jadi, alih-alih [email protected]Anda harus menulis "a..b"@example.net, yang secara semantik setara.

Pembatasan lebih lanjut

SMTP (sebagaimana didefinisikan dalam RFC 5321 ) lebih lanjut membatasi rangkaian alamat email yang valid (atau sebenarnya: nama kotak surat). Tampaknya masuk akal untuk menerapkan tata bahasa yang lebih ketat ini, sehingga alamat email yang cocok sebenarnya dapat digunakan untuk mengirim email.

RFC 5321 pada dasarnya menyisakan bagian "lokal" (yaitu bagian sebelum tanda @), tetapi lebih ketat pada bagian domain (yaitu bagian setelah tanda @). Ini memungkinkan hanya nama host yang menggantikan dot-atom dan address literal sebagai pengganti literal domain.

Tata bahasa yang disajikan dalam RFC 5321 terlalu lunak jika menyangkut nama host dan alamat IP. Saya mengambil kebebasan untuk "memperbaiki" aturan yang dimaksud, menggunakan konsep ini dan RFC 1034 sebagai pedoman. Inilah regex yang dihasilkan.

([-!#-'*+/-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^-~]+)])

Perhatikan bahwa tergantung pada kasus penggunaan, Anda mungkin tidak ingin mengizinkan "General-address-literal" di regex Anda. Juga perhatikan bahwa saya menggunakan lookahead negatif (?!IPv6:)di regex akhir untuk mencegah bagian "General-address-literal" untuk mencocokkan alamat IPv6 yang salah. Beberapa prosesor regex tidak mendukung tampilan negatif. Hapus substring |(?!IPv6:)[0-9A-Za-z-]*[0-9A-Za-z]:[!-Z^-~]+dari regex jika Anda ingin mengeluarkan seluruh bagian "General-address-literal".

Inilah derivasi:

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^-~]+)])

Validasi input pengguna

Kasing penggunaan umum adalah validasi input pengguna, misalnya pada formulir html. Dalam hal ini, biasanya masuk akal untuk mencegah literal alamat dan membutuhkan setidaknya dua label dalam nama host. Mengambil regex RFC 5321 yang ditingkatkan dari bagian sebelumnya sebagai dasar, ekspresi yang dihasilkan adalah:

([-!#-'*+/-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])?)+

Saya tidak merekomendasikan untuk membatasi bagian lokal lebih lanjut, misalnya dengan menghalangi string yang dikutip, karena kita tidak tahu jenis nama kotak surat apa yang dibolehkan oleh beberapa host (suka "a..b"@example.netatau bahkan "a b"@example.net).

Saya juga tidak merekomendasikan memvalidasi secara eksplisit terhadap daftar domain tingkat atas literal atau bahkan memaksakan batasan panjang (ingat bagaimana ".museum" tidak valid [a-z]{2,4}), tetapi jika Anda harus:

([-!#-'*+/-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|dll ...)

Pastikan untuk tetap memperbarui regex Anda jika Anda memutuskan untuk turun ke jalur validasi domain tingkat atas eksplisit.

Pertimbangan lebih lanjut

Ketika hanya menerima nama host di bagian domain (setelah tanda @), regex di atas hanya menerima label dengan paling banyak 63 karakter, sebagaimana seharusnya. Namun, mereka tidak memaksakan fakta bahwa seluruh nama host harus paling panjang 253 karakter (termasuk titik-titik). Meskipun batasan ini secara tegas masih teratur, itu tidak layak untuk membuat regex yang menggabungkan aturan ini.

Pertimbangan lain, terutama ketika menggunakan regex untuk validasi input, adalah umpan balik kepada pengguna. Jika pengguna memasukkan alamat yang salah, alangkah baiknya memberikan sedikit lebih banyak umpan balik daripada "alamat yang salah secara sintaksis" yang sederhana. Dengan regex "vanilla" ini tidak mungkin.

Kedua pertimbangan ini dapat diatasi dengan menguraikan alamat. Batasan panjang ekstra pada nama host dalam beberapa kasus juga dapat diatasi dengan menggunakan regex tambahan yang memeriksanya, dan mencocokkan alamat dengan kedua ekspresi.

Tidak ada regex dalam jawaban ini yang dioptimalkan untuk kinerja. Jika kinerja merupakan masalah, Anda harus melihat apakah (dan bagaimana) regex pilihan Anda dapat dioptimalkan.

Rinke
sumber
3
RFC 6532 memperbarui 5322 untuk memungkinkan dan menyertakan UTF-8 yang lengkap dan bersih. Detail tambahan di sini .
Menurut wikipedia tampaknya bagian lokal, ketika bertitik, memiliki batasan 64 karakter per bagian, dan juga RFC 5322 merujuk pada bagian lokal bertitik untuk ditafsirkan dengan pembatasan domain. Misalnya 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.comtidak boleh memvalidasi. Saya sarankan mengubah tanda "+" di grup pertama (nama sebelum titik opsional) dan di grup kedua (nama setelah titik-titik berikut) ke{1,64}
Xavi Montero
Karena komentar terbatas dalam ukuran, inilah regex yang dihasilkan yang saya rencanakan untuk digunakan, yang merupakan jawaban di awal jawaban ini, ditambah membatasi ukuran di bagian lokal, ditambah menambahkan garis miring sebelum "/" simbol seperti yang dipersyaratkan oleh PHP dan juga di regex101.com: Di PHP saya menggunakan:$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
PERHATIAN: Untuk beberapa alasan, StackOverflow menambahkan karakter tersembunyi saat menyalin dari penurunan harga yang diberikan. Salin ke regex101.com dan Anda akan melihat titik-titik hitam di sana. Anda harus menghapusnya dan memperbaiki string ... Mungkin jika diintegrasikan dalam jawabannya, mereka dapat disalin dengan benar. Maaf untuk ketidaknyamanannya. Saya tidak ingin menambahkan jawaban baru karena ini adalah jawaban yang tepat. Juga saya tidak ingin mengedit secara langsung kecuali jika komunitas berpikir ini harus diintegrasikan ke dalamnya.
Xavi Montero
@XaviMontero Thaks untuk berkontribusi Xavi! Apakah Anda memiliki referensi ke RFC yang menyatakan batas 64 karakter pada label bagian lokal? Jika demikian, saya akan dengan senang hati menyesuaikan jawabannya.
Rinke
73

Ada banyak contoh hal ini di internet (dan saya pikir bahkan satu yang sepenuhnya memvalidasi RFC - tapi itu puluhan / ratusan baris lama jika ingatanku). Orang-orang cenderung terbujuk untuk membuktikan hal semacam ini. Mengapa tidak memeriksa saja apakah ada @ dan setidaknya satu. dan memenuhi beberapa panjang minimum sederhana. Sepele untuk memasukkan email palsu dan tetap cocok dengan regex yang valid. Saya kira positif palsu lebih baik daripada negatif palsu.

Draemon
sumber
1
Ya, tapi RFC yang mana ? :) Ini [RFC ‐ 5322 – validator] ( stackoverflow.com/questions/201323/… ) hanya panjangnya sekitar empat puluh baris.
tchrist
14
SEBUAH . tidak diperlukan. TLD dapat memiliki alamat email, atau mungkin ada alamat IPv6
Sijmen Mulder
1
RFC bukanlah akhir dari cerita: ICANN tidak lagi mengizinkan domain 'tanpa titik': icann.org/news/announcement-2013-08-30-en
Synchro
64

Saat memutuskan karakter mana yang diperbolehkan, harap ingat teman Anda yang telah ditulis ulang dan ditulis dengan tanda penghubung. Saya tidak memiliki kendali atas kenyataan bahwa perusahaan saya menghasilkan alamat email saya menggunakan nama saya dari sistem SDM. Itu termasuk tanda kutip di nama belakang saya. Saya tidak dapat memberi tahu Anda berapa kali saya diblokir untuk berinteraksi dengan situs web oleh fakta bahwa alamat email saya "tidak valid".

DOK
sumber
4
Ini adalah masalah yang sangat umum dalam program yang membuat asumsi yang tidak beralasan tentang apa yang bisa dan tidak diizinkan atas nama seseorang. Seseorang seharusnya tidak membuat asumsi seperti itu, hanya menerima karakter apa pun yang menurut RFC yang relevan harus dilakukan.
tchrist
4
Iya. Saya sangat marah terhadap programmer yang menolak huruf kapital di alamat email! Konyol dan / atau malas.
PhiLho
63

Regex ini dari Perl's Email :: Valid library. Saya percaya ini yang paling akurat, cocok dengan semua 822. Dan, ini didasarkan pada ekspresi reguler dalam buku O'Reilly:

Ekspresi reguler dibuat menggunakan contoh Jeffrey Friedl dalam Menguasai Ekspresi Reguler ( 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
Evan Carroll
sumber
14
O_O Anda juga harus menjadi master regex untuk memahami apa yang dilakukannya
Chris McGrath
45

Saat Anda menulis dalam PHP, saya akan menyarankan Anda untuk menggunakan validasi bawaan PHP untuk email.

filter_var($value, FILTER_VALIDATE_EMAIL)

Jika Anda menjalankan versi php lebih rendah dari 5.3.6 harap perhatikan masalah ini: https://bugs.php.net/bug.php?id=53091

Jika Anda ingin informasi lebih lanjut bagaimana validasi buid-in ini berfungsi, lihat di sini: Apakah filter_var PHP FILTER_VALIDATE_EMAIL sebenarnya berfungsi?

SimonSimCity
sumber
mendapat suara, persis apa yang akan saya katakan. Tidak menangani IDN tetapi mengonversi ke kode lemah sebelumnya menyelesaikan ini. PHP> = 5.3 memiliki idn_to_ascii () untuk ini. Salah satu cara terbaik dan termudah untuk memvalidasi email.
Taylor
43

Cal Henderson (Flickr) menulis sebuah artikel yang disebut Parsing Email Adresses di PHP dan menunjukkan bagaimana melakukan parsing Alamat Email yang sesuai dengan RFC (2) 822. Anda juga bisa mendapatkan kode sumber dalam php , python dan ruby ​​yang berlisensi cc .

adnam
sumber
itu mengatakan kepada saya bahwa a@bitu valid
dsdsdsdsd
1
@dsdsdsdsd Karena a@bvalid ... dalam hal ini badalah domain tingkat atas.
rink.attendant.6
42

Saya tidak pernah repot mencipta dengan ekspresi reguler saya sendiri, karena kemungkinan orang lain telah membuat versi yang lebih baik. Saya selalu menggunakan regexlib untuk menemukan yang sesuai dengan keinginan saya.

Kon
sumber
1
Ini ditandai untuk panjang dan konten, tetapi kontribusi masih bagus dengan 41 suara dan tidak boleh dihapus.
Will
37

Tidak ada satu yang benar-benar dapat digunakan.
Saya membahas beberapa masalah dalam jawaban saya untuk Apakah ada perpustakaan php untuk validasi alamat email? , dibahas juga dalam Regexp pengakuan alamat email yang sulit?

Singkatnya, jangan berharap satu regex yang dapat digunakan untuk melakukan pekerjaan yang tepat. Dan regex terbaik akan memvalidasi sintaks, bukan validitas email ([email protected] benar tetapi mungkin akan terpental ...).

PhiLho
sumber
Perbaiki saya jika saya salah, tetapi saya percaya bahwa PHP menggunakan pola PCRE. Jika demikian, Anda harus dapat membuat sesuatu yang mirip dengan pola RFC 5322 Abigail .
tchrist
@tchrist: tidak yakin apakah PCRE telah menangkap sintaks ini (yang saya temukan). Jika demikian, tidak yakin apakah PHP PCRE telah mencapai versi PCRE ini ... Ya, jika saya memahami sintaks ini dengan benar, Anda juga dapat menggunakan parser PEG, lebih jelas dan lengkap daripada regex.
PhiLho
PCRE telah menangkapnya, tetapi mungkin PHP belum menyusul PCRE. ☹
tchrist
36

Satu ungkapan reguler sederhana yang setidaknya tidak akan menolak alamat email yang valid adalah memeriksa sesuatu, diikuti oleh tanda @ dan kemudian sesuatu diikuti oleh tanda titik dan setidaknya 2 tanda sesuatu. Itu tidak akan menolak apa pun, tetapi setelah memeriksa spesifikasi, saya tidak dapat menemukan email apa pun yang valid dan ditolak.

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

spig
sumber
3
Ini yang saya cari. Tidak terlalu membatasi, tetapi pastikan hanya ada 1 @ (karena kami menguraikan daftar dan ingin memastikan tidak ada koma yang hilang). FYI, Anda dapat memiliki @ di sebelah kiri jika dalam tanda kutip: Valid_email_addresses , tetapi itu sangat pinggiran.
Josh
2
Setelah menggunakannya, menyadari itu tidak bekerja dengan tepat. /^[^@]+@[^@]+\.[^@]{2}[^@]*$/ sebenarnya memeriksa 1 tanda @. Regex Anda akan membiarkan banyak masuk karena. * Pada akhirnya.
Josh
1
Baik. Saya tidak mencoba untuk menolak semua yang tidak valid, hanya terus menolak alamat email yang valid.
spig
1
Akan jauh lebih baik menggunakan ini: /^[^@]+@[^@]+\.[^@]{2,4}$/memastikan bahwa itu diakhiri dengan 2 hingga 4 non @ karakter. Seperti yang ditunjukkan oleh @Josh, sekarang memungkinkan @ ekstra pada akhirnya. Tetapi Anda juga dapat mengubahnya juga menjadi: /^[^@]+@[^@]+\.[^a-z-A-Z]{2,4}$/karena semua domain tingkat atas adalah karakter aZ. Anda dapat mengganti 4dengan 5atau lebih memungkinkan nama domain tingkat atas menjadi lebih lama di masa depan juga.
FLY
@ FLY, ka @ foo. mengembalikan yang benar. Apakah seharusnya menurut standar?
SexyBeast
29

Anda bisa menggunakan yang digunakan oleh plugin Validasi jQuery:

/^((([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
kekacauan
sumber
ini tampaknya melakukan pekerjaan dengan baik. Itu diperbolehkan: a-b'[email protected]tetapi mampu menangkap variasi yang tidak pantas, seperti a-b'[email protected]dana-b'[email protected]
dsdsdsdsd
25

Untuk evaluasi terlengkap dari ekspresi reguler terbaik untuk memvalidasi alamat email, lihat tautan ini; " Membandingkan Alamat E-mail yang Memvalidasi Ekspresi Reguler "

Berikut adalah ekspresi teratas saat ini untuk tujuan referensi:

/^([\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
Eric Schoonover
sumber
spoon16: Tautan itu tidak benar. Pernyataannya bahwa tidak ada pola yang sempurna untuk memvalidasi alamat email adalah kesalahan. Anda bisa , tetapi Anda harus memastikan bahwa Anda mengikuti RFC sampai ke surat itu. Dan Anda harus memilih RFC yang tepat juga.
tchrist
Yang "terbaik" saat ini tidak berfungsi dengan java regex - bahkan setelah keluar dan mengubah string dengan benar.
Eric Chen
23

Belum lagi bahwa nama domain non-Latin (Cina, Arab, Yunani, Ibrani, Sirilik, dan sebagainya) akan diizinkan dalam waktu dekat . Setiap orang harus mengubah regex email yang digunakan, karena karakter-karakter itu pasti tidak akan dicakup oleh [a-z]/imaupun \w. Mereka semua akan gagal.

Setelah semua, cara terbaik untuk memvalidasi alamat email masih benar-benar mengirim email ke alamat yang dimaksud untuk memvalidasi alamat. Jika alamat email adalah bagian dari otentikasi pengguna (daftar / login / dll), maka Anda dapat menggabungkannya dengan sempurna dengan sistem aktivasi pengguna. Yaitu mengirim email dengan tautan dengan kunci aktivasi unik ke alamat email yang ditentukan dan hanya mengizinkan login ketika pengguna telah mengaktifkan akun yang baru dibuat menggunakan tautan dalam email tersebut.

Jika tujuan regex hanya untuk dengan cepat memberi tahu pengguna di UI bahwa alamat email yang ditentukan tidak terlihat dalam format yang benar, yang terbaik adalah masih memeriksa apakah itu pada dasarnya cocok dengan regex berikut:

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

Sederhana seperti itu. Mengapa Anda peduli dengan karakter yang digunakan dalam nama dan domain? Adalah tanggung jawab klien untuk memasukkan alamat email yang valid, bukan server. Bahkan ketika klien memasukkan alamat email yang valid secara sintaksis seperti [email protected], ini tidak menjamin bahwa itu adalah alamat email yang sah. Tidak ada satu regex yang bisa mengatasinya.

BalusC
sumber
4
Saya setuju bahwa mengirim pesan otentikasi biasanya merupakan cara terbaik untuk hal-hal semacam ini, secara sintaksis benar dan valid tidak sama. Saya merasa frustrasi ketika saya harus mengetik alamat email saya dua kali untuk "Konfirmasi" seolah-olah saya tidak bisa melihat apa yang saya ketik. Saya hanya menyalin yang pertama ke yang kedua, sepertinya semakin sering digunakan.
PeteT
setuju! tapi saya pikir regex ini tidak valid karena memungkinkan spacessetelah @.eg. [email protected] com netdianggap email yang valid dengan menggunakan regex di atas yang seharusnya tidak valid.
CB4
20

Spesifikasi HTML5 menyarankan regex sederhana untuk memvalidasi alamat email:

/^[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])?)*$/

Ini dengan sengaja tidak mematuhi RFC 5322 .

Catatan: Persyaratan ini adalah pelanggaran yang disengaja dari RFC 5322 , yang mendefinisikan sintaks untuk alamat e-mail yang bersamaan terlalu ketat (sebelum @karakter), terlalu samar (setelah @karakter), dan terlalu longgar (mengizinkan komentar, karakter spasi, dan mengutip string dalam perilaku yang tidak dikenal oleh sebagian besar pengguna) agar praktis digunakan di sini.

Total panjang juga dapat dibatasi hingga 254 karakter, per RFC 3696 errata 1690 .

Ross Allan
sumber
Jawaban Terbaik! Berikut tautan ke rekomendasi w3: w3.org/TR/html5/forms.html#valid-e-mail-address Regex ini diadopsi oleh banyak browser.
Ryan Taylor
3
Ini SANGAT bukan jawaban terbaik! Pola ini sesuai alamat yang sepenuhnya tidak valid ini: invalid@emailaddress. Saya akan mendorong hati-hati dan banyak pengujian sebelum Anda menggunakannya!
Sheridan
@ Sheridan, jika Anda berpikir ada masalah dengan spesifikasi HTML5 Anda dapat mengajukan masalah di sini: github.com/w3c/html/issues
Luna
Ini tidak menambah lebih dari stackoverflow.com/a/8829363 dan akankah IMHO lebih baik sebagai edit atau komentar tentang itu.
contoh @ localhost valid, tetapi untuk aplikasi dunia nyata Anda mungkin ingin menerapkan ekstensi domain, yang perlu Anda lakukan adalah mengubah * akhir menjadi + untuk mencapai ini (mengubah bagian dari pola dari 0+ ke 1+ )
Mitch Satchwell
15

Untuk demonstrasi yang jelas, monster berikut ini cukup bagus tetapi masih tidak mengenali semua alamat email yang valid secara sintaksis: ia mengenali komentar yang bersarang hingga kedalaman empat level.

Ini adalah pekerjaan untuk parser, tetapi bahkan jika suatu alamat secara sintaksis valid, itu masih mungkin tidak dapat dikirim. Kadang-kadang Anda harus menggunakan metode perbukitan "Hei, kalian semua, awasi kami!"

// 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); 
Greg Bacon
sumber
12

Menurut standar resmi RFC 2822 regex email yang valid adalah

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

jika Anda ingin menggunakannya di Jawa itu sangat sangat mudah

import java.util.regex.*;

class regexSample 
{
   public static void main(String args[]) 
   {
      //Input the string for validation
      String email = "[email protected]";

      //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.");
   }
}
AZ_
sumber
1
Regex Anda tidak menyertakan huruf besar pertama misalnya [email protected] yang dapat mengganggu sebagian pengguna. Gunakan yang ini sebagai gantinya:(?:[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 Terima kasih, harap edit jawabannya, saya akan menerima kembaliannya.
AZ_
Jika saya menambahkan perubahan itu ke jawaban Anda itu tidak akan menjadi RFC 2822 lagi jadi saya tidak tahu apakah itu benar.
Kebab Krabby
11

Inilah PHP yang saya gunakan. Saya telah memilih solusi ini dengan semangat "false positive lebih baik daripada false negative" sebagaimana dinyatakan oleh komentator lain di sini DAN sehubungan dengan menjaga waktu tanggapan Anda dan server memuat ... benar-benar tidak perlu membuang sumber daya server dengan ekspresi reguler saat ini akan menghilangkan kesalahan pengguna yang paling sederhana. Anda selalu dapat menindaklanjuti ini dengan mengirim email uji jika Anda mau.

function validateEmail($email) {
  return (bool) stripos($email,'@');
}
Mac
sumber
1
a) "sumber daya server limbah" sangat kecil, tetapi jika Anda cenderung, Anda dapat melakukannya di sisi klien dengan JS b) Apa yang Anda perlukan untuk mengirim surat registrasi dan pengguna memasukkan saya @ forgetthedotcom? "Solusi" Anda gagal dan Anda kehilangan pengguna.
johnjohn
a) Mengandalkan validasi JS yang akan gagal ketika JavaScript dinonaktifkan tidak terdengar seperti ide terbaik (hanya btw)
auco
11

RFC 5322 standar:

Mengizinkan dot-atom bagian lokal, bagian-string yang dikutip-lokal, bagian lokal yang usang (campuran dot-atom dan string-dikutip), domain nama domain, (IPv4, IPv6, dan alamat IPv6 yang dipetakan IPv4) domain domain literal, dan (bersarang) 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 standar:

Mengizinkan dot-atom lokal-bagian, string-lokal-dikutip, domain nama domain, dan (IPv4, IPv6, dan alamat IPv6 yang dipetakan IPv4) domain domain literal.

'/^(?!(?>"?(?>\\\[ -~]|[^"])"?){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'

Dasar:

Mengizinkan dot-atom bagian lokal dan domain nama domain (membutuhkan setidaknya dua label nama domain dengan TLD terbatas pada 2-6 karakter alfabet).

"/^(?!.{255,})(?!.{65,}@)([!#-'*+\/-9=?^-~-]+)(?>\.(?1))*@(?!.*[^.]{64,})(?>[a-z0-9](?>[a-z0-9-]*[a-z0-9])?\.){1,126}[a-z]{2,6}$/iD"
MichaelRushton
sumber
Apa bahasa iblis itu ?? Saya melihat /Dbendera, dan Anda telah mengutipnya dengan tanda kutip tunggal namun juga menggunakan garis miring untuk membatasi pola? Ini bukan Perl, dan itu tidak bisa PCRE. Apakah itu PHP? Saya percaya itu adalah tiga-satunya yang memungkinkan rekursi seperti (?1).
tchrist
Itu dalam PHP, yang menggunakan PCRE. Garis miring hanya digunakan untuk membatasi karakter khusus seperti tanda kurung, tanda kurung, dan tentu saja garis miring dan kutipan tunggal. Bendera / D, jika Anda tidak tahu, adalah untuk mencegah baris baru ditambahkan ke akhir string, yang akan diizinkan sebaliknya.
MichaelRushton
9

Aneh bahwa Anda "tidak bisa" mengizinkan 4 karakter TLD. Anda melarang orang-orang dari .info dan .name , dan keterbatasan panjang berhenti .travel dan .museum , tapi ya, mereka kurang umum daripada 2 karakter TLDs dan 3 karakter TLDs.

Anda juga harus mengizinkan huruf besar. Sistem email akan menormalkan bagian lokal dan bagian domain.

Untuk regex bagian domain Anda, nama domain tidak dapat dimulai dengan '-' dan tidak dapat diakhiri dengan '-'. Dash hanya bisa tetap di antaranya.

Jika Anda menggunakan perpustakaan PEAR, periksa fungsi surat mereka (lupa nama / perpustakaan yang tepat). Anda dapat memvalidasi alamat email dengan memanggil satu fungsi, dan itu memvalidasi alamat email sesuai dengan definisi dalam RFC822.

Joseph Yee
sumber
2
@ Joseph Yee: Bukankah RFC 822 agak ketinggalan jaman?
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;
    }
}
Murthy Jeedigunta
sumber