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;
}
}
我仍在使用:
^[A-Za-z0-9._+\-\']+@[A-Za-z0-9.\-]+\.[A-Za-z]{2,}$
console.log(/^[\p{L}!#-'*+\-/\d=?^-~]+(.[\p{L}!#-'*+\-/\d=?^-~])*@[^@\s]{2,}$/u.test("תה.בועות@.fm"))
Gmail允许使用连续的点,但Microsoft Exchange Server 2007不允许,这符合我了解到的最新标准。
"John Smith"@example.com
。 - David Conrad/^[^@\s]+@[^@\s]+$/
2. 如果第一个验证器未通过(对于大多数地址而言,它应该通过,尽管不是完美的),则警告用户该电子邮件无效,并不允许他/她继续输入。电子邮件地址的正则表达式为:
/^("(?:[!#-\[\]-\u{10FFFF}]|\\[\t -\u{10FFFF}])*"|[!#-'*+\-/-9=?A-Z\^-\u{10FFFF}](?:\.?[!#-'*+\-/-9=?A-Z\^-\u{10FFFF}])*)@([!#-'*+\-/-9=?A-Z\^-\u{10FFFF}](?:\.?[!#-'*+\-/-9=?A-Z\^-\u{10FFFF}])*|\[[!-Z\^-\u{10FFFF}]*\])$/u
addr-spec
ABNF完全相同,如RFC 5321, RFC 5322,和RFC 6532中所指定。此外,您还需要验证以下内容:最简单的方法是使用现有的函数。在PHP中,可以使用filter_var函数,使用FILTER_VALIDATE_EMAIL
和FILTER_FLAG_EMAIL_UNICODE
(如果您可以发送到国际化电子邮件地址):
$email_valid = filter_var($email_input, FILTER_VALIDATE_EMAIL, FILTER_FLAG_EMAIL_UNICODE);
然而,也许你正在构建这样一个功能——实现这个最简单的方法是使用正则表达式。
请记住,这仅验证电子邮件地址不会导致语法错误。验证地址是否能够接收电子邮件的唯一方法是实际地发送一封电子邮件。
接下来,我将介绍如何生成这个正则表达式。
完全可以从ABNF制作正则表达式,只要没有递归部分。
RFC 5322指定在MIME消息中发送什么是合法的;将其视为合法电子邮件地址的上限。
但是,严格按照这个ABNF进行操作是错误的:该模式技术上表示如何在MIME消息中编码电子邮件地址,并允许不属于电子邮件地址的字符串,例如折叠空格和注释;它还包括不合法生成的过时形式的支持(但服务器出于历史原因会读取)。 电子邮件地址不包括这些内容。
RFC 5322解释:
“atom”和“dot-atom”都被解释为单个单位,包括构成它的字符串。从语义上讲,其余字符周围的可选注释和FWS不是该原子的一部分;原子只是原子中atext字符的运行或者dot-atom中atext和“.”字符的运行。
在某些定义中,将会有以“obs-”开头的非终结符。这些“obs-”元素指的是第4节中定义的过时语法中的标记。在所有情况下,这些产生式应被忽略,以生成合法的Internet消息,并且不能作为此类消息的一部分使用。
如果从RFC 5322的addr-spec
中删除CFWS
、BWS
和obs-*
规则,并对结果进行一些优化(我使用了"greenery"),则可以生成此正则表达式,用斜杠引用并锚定(适用于ECMAScript和兼容方言,为了清晰起见添加了换行符):
/^("(?:[!#-\[\]-~]|\\[\t -~])*"|[!#-'*+\-/-9=?A-Z\^-~](?:\.?[!#-'*+\-/-9=?A-Z\^-~])*)
@([!#-'*+\-/-9=?A-Z\^-~](?:\.?[!#-'*+\-/-9=?A-Z\^-~])*|\[[!-Z\^-~]*\])$/
这仅支持ASCII电子邮件地址。要支持RFC 6532国际化电子邮件地址,请将~
字符替换为\u{10FFFF}
(PHP、带有u
标志的ECMAScript),或\uFFFF
(适用于UTF-16实现,如.NET和旧版ECMAScript / JavaScript):
/^("(?:[!#-\[\]-\u{10FFFF}]|\\[\t -\u{10FFFF}])*"|[!#-'*+\-/-9=?A-Z\^-\u{10FFFF}](?:\.?[!#-'*+\-/-9=?A-Z\^-\u{10FFFF}])*)@([!#-'*+\-/-9=?A-Z\^-\u{10FFFF}](?:\.?[!#-'*+\-/-9=?A-Z\^-\u{10FFFF}])*|\[[!-Z\^-\u{10FFFF}]*\])$/u
@
之前)可以是点原子或带引号的字符串。"([!#-\[\]-~]|\\[\t -~])*"
指定了用户的带引号字符串形式,例如 "root@home"@example.com
。它允许双引号内的任何非控制字符;除了空格、制表符、双引号和反斜杠必须被反斜杠转义。[!#-'*+\-/-9=?A-Z\^-~]
是用户的点原子的第一个字符。(\.?[!#-'*+\-/-9=?A-Z\^-~])*
匹配剩余的点原子,允许使用点(除了在另一个点后面或作为最后一个字符)。@
表示域名。[!#-'*+\-/-9=?A-Z\^-~](\.?[!#-'*+\-/-9=?A-Z\^-~])*
与上述相同的点原子形式,但此处表示域名和IPv4地址。\[[!-Z\^-~]*\]
将匹配IPv6地址和主机名的未来定义。match[1]
是用户,match[2]
是主机。(但是如果match[1]
以双引号开头,则过滤掉反斜杠转义、开始和结束的双引号:"root"@example.com
和root@example.com
标识相同的收件箱。)@
字符,在UTF-8编码后,整个地址的限制为320个字节。这是以字节为单位衡量的,而不是字符。addr-spec = local-part "@" domain
local-part = dot-atom / quoted-string / obs-local-part
domain = dot-atom / domain-literal / obs-domain
domain-literal = [CFWS] "[" *([FWS] dtext) [FWS] "]" [CFWS]
dtext = %d33-90 / ; Printable US-ASCII
%d94-126 / ; characters not including
obs-dtext ; "[", "]", or "\"
我知道这个问题是关于正则表达式的,但是我猜想阅读这些解决方案的90%开发人员都在尝试验证在浏览器中显示的HTML表单中的电子邮件地址。
如果是这种情况,我建议使用新的HTML5 <input type="email">
表单元素:
HTML5:
<input type="email" required />
CSS 3:
input:required {
background-color: rgba(255, 0, 0, 0.2);
}
input:focus:invalid {
box-shadow: 0 0 1em red;
border-color: red;
}
input:focus:valid {
box-shadow: 0 0 1em green;
border-color: green;
}
这是在HTML5表单验证无需JS - JSFiddle - 代码游乐场。
这有几个优点:
显而易见的缺点可能是老式浏览器的验证丢失,但这将随着时间的推移而改变。 我宁愿选择这个而不是那些疯狂的正则表达式杰作。
另请参见:
这个规则匹配的是我们的Postfix服务器无法发送的内容。
允许使用字母、数字、-、_、+、.、&、/和!
不允许-foo@bar.com
不允许asd@-bar.com
/^([a-z0-9\+\._\/&!][-a-z0-9\+\._\/&!]*)@(([a-z0-9][-a-z0-9]*\.)([-a-z0-9]+\.)*[a-z]{2,})$/i
对于PHP,我使用Nette框架的电子邮件地址验证器:(点击此处查看源代码)
/* public static */ function isEmail($value)
{
$atom = "[-a-z0-9!#$%&'*+/=?^_`{|}~]"; // RFC 5322 unquoted characters in local-part
$localPart = "(?:\"(?:[ !\\x23-\\x5B\\x5D-\\x7E]*|\\\\[ -~])+\"|$atom+(?:\\.$atom+)*)"; // Quoted or unquoted
$alpha = "a-z\x80-\xFF"; // Superset of IDN
$domain = "[0-9$alpha](?:[-0-9$alpha]{0,61}[0-9$alpha])?"; // RFC 1034 one domain component
$topDomain = "[$alpha](?:[-0-9$alpha]{0,17}[$alpha])?";
return (bool) preg_match("(^$localPart@(?:$domain\\.)+$topDomain\\z)i", $value);
}
对于我来说,正确检查电子邮件地址的方法是:
/^[^@]+@[^@]+$/
当然,你可以在前端显示一些警告或工具提示,以帮助用户避免常见错误,比如域名部分没有点或名称中有空格但没有引用等。但是如果用户确实需要输入“hello@world”,则必须接受该地址。
此外,需要记住电子邮件地址标准曾经发生过变化,可能还会不断地演变,因此不能只使用一次“标准有效”的正则表达式。同时,需要记住一些具体的互联网服务器可能会有一些细节上的问题,这些与共同使用的标准不同,事实上采用了自己修改过的标准。
因此,只需检查@,在前端提示用户并向给定的地址发送验证电子邮件即可。
^((([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])))\.?$