这个用于验证电子邮件的正则表达式有什么问题?

7

以下是验证电子邮件的正则表达式 - \S+@\S+\.\S+,我没有写这个正则表达式。作为一个新手,我对正则表达式不是很熟悉,以下是我的几个问题:

  1. 上面的正则表达式有什么错误?
  2. 什么是一个好的验证电子邮件的正则表达式?

3
谁想成为第一个发布三页电子邮件正则表达式的人? - Michael Myers
4
关于这个问题的原因:首先,它不允许在第一部分中使用句点,这将使我三个电子邮件地址中的两个被淘汰。其次,在第二部分中它只允许一个句点,这将淘汰例如“.co.uk”这样的域名。 - Michael Myers
3
该系统不允许在用户名中使用加号“+”符号,但这是合法的。加号后面的部分会被忽略,但很多人会将其用于邮件过滤。例如,给定用户名" user@gmail.com ",有人可能会使用" user+amazon@gmail.com "作为亚马逊的电子邮件地址,以便于过滤邮件(或跟踪某个服务是否将他们的电子邮件地址提供给另一个服务)。 - mipadi
3
你的意思是,“不允许”的意思是什么?\S 匹配任何非空格字符。 - Alan Moore
2
确实,Alan是正确的。mipadimmyers,你们两个都错了:\S匹配.(点)和+ - Bart Kiers
显示剩余4条评论
6个回答

18
"如何使用正则表达式验证电子邮件地址" 是关于正则表达式的一个较为流行的问题之一,但唯一真正好的答案是 "你不需要"。在这个网站上已经讨论过这个问题 多次您需要明白的是,如果您真的想遵循规范,您的正则表达式看起来会像这样。显然,这是一个丑陋的东西,更多的是为了演示按照规定接受电子邮件的困难程度。因此,如果您绝对需要确保电子邮件地址是有效的,唯一可靠的方法是实际发送一封消息到该电子邮件地址并检查是否存在退信。否则,这个正则表达式可以正确验证大多数情况,而在许多情况下,大多数情况已经足够了。此外,该页面还将讨论尝试使用正则表达式验证电子邮件地址时可能遇到的问题。

7
我只会回答你的第一个问题,从技术正则表达式的角度来看。正则表达式\S+@\S+\.\S+的问题在于它有可能执行得太慢了。如果有人输入以下这样的电子邮件字符串,并且您需要验证它,会发生什么呢?
a@b.cdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz0123456789
甚至更糟糕的是(是的,在点号后面有100个@):
@.@@@@@@@@@@@@@@@@@@@@@@@@@ \ @@@@@@@@@@@@@@@@@@@@@@@@@ \ @@@@@@@@@@@@@@@@@@@@@@@@@ \ @@@@@@@@@@@@@@@@@@@@@@@@@
会出现缓慢的情况。首先,正则表达式会贪婪地匹配尽可能多的字符,直到第一个\S+。因此,它最初将匹配整个字符串。然后我们需要@字符,所以它会回溯直到找到一个。此时我们又有了一个\S+,所以它又会消耗掉直到字符串结束的所有内容。然后它需要再次回溯,直到找到一个点。你能想象在第二个电子邮件字符串中正则表达式失败之前会有多少回溯吗?
为了杀死回溯,我建议在这种情况下使用占有字符类,这还有一个额外的好处,即不允许一个字符串中有多个@。
[^@\s]++@[^@\s.]++\.[^@\s]++
我针对“100 @'s电子邮件”测试了这两个正则表达式的速度。我的速度大约快95倍。

1
嗨,Geert,很高兴在这里见到你。关于正则表达式的执行时间:我认为在这种情况下这并不重要,除非您要在很短的时间内验证数千个地址或者地址有数千个字符长。(但我们之前已经讨论过这个问题了 :))。 祝好,Bart(prometheuzz)。 - Bart Kiers
我不禁想知道宽容正则表达式比庞大的RFC正则表达式慢多少,我猜它仍然比后者快得多,因此在这种情况下,性能似乎不是一个主要问题。基本上,95倍于1毫秒的速度只有95毫秒,可以忽略不计。那么我们在这里谈论的是什么样的减速? - Kzqai

2
我看到@liam发布了RFC822的链接。但是,为了保持stackoverflow是一个目的地的想法,并且以防ex-parrot.com删除链接或其他情况。整个内容如下:

Mail :: RFC822 :: Address:基于正则表达式的地址验证

Mail :: RFC822 :: Address是一个Perl模块,用于根据RFC 822语法验证电子邮件地址。它提供与RFC :: RFC822 :: Address相同的功能,但使用Perl正则表达式而不是Parse :: RecDescent解析器。这意味着该模块加载速度更快,因为它不需要在启动时编译语法。

下载 Mail::RFC822::Address-0.4.tar.gz阅读文档
RFC 822 中描述的语法异常复杂。使用正则表达式实现验证有点超出了正则表达式的合理应用极限,不过 Perl 处理得很好。
(?:(?:\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*)

这个正则表达式只会验证地址,其中任何注释都已被删除并替换为空格(这是由模块完成的)。

2
上面的正则表达式有什么问题? 它只检查@和.。有很多肯定不合法的电子邮件地址会匹配这个组合。例如,如果一个人写了user@www.myWebsite.com,它会匹配,但显然是一个错误。更复杂的正则表达式将会捕获这种错误并帮助用户。同样的,如果他输入了user@myWebsite.nt - 他拼错了'net'。或者他输入了两个@@(user@@yahoo.com/user@yahoo@yahoo.com - 这实际上相当普遍),或者两个点(user@yahoo..com)。一个更好的正则表达式应该会捕获这些。 如果你不想太挑剔,你甚至不需要一个正则表达式。indexOf('@') !=-1 就能捕获大部分错误。一旦检查,你应该做得更好。
好的验证电子邮件的正则表达式是什么?可以参考这两个链接:http://www.gooli.org/blog/useful-regular-expressionshttp://www.regular-expressions.info/email.html

4
user@www.myWebsite.com 是一个有效的电子邮件地址。 - Andrew Moore
真的吗?如果我输入myName@www.yahoo.com,我会得到它吗?虽然现在我想了想,以.nt结尾的东西也可能是。捕获和验证上述两者仍然是正确的。 - SamGoody
1
在电子邮件的后半部分,例如johnny@corporate.example.com中经常有多个点是很常见的。 - Funka

0
虽然我有点晚了,但这可能对仍然想要查看更多的人有所帮助。
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
  // invalid email address
}

这只会验证电子邮件格式是否正确。但是如果你想使用更多的功能,比如验证该电子邮件是否真实存在,你需要使用一些邮件验证API。
以下是我目前在我的网站上使用的代码。
    if(isEmialExist("EMAIL_ADDRESS_THAT"))
{
    echo "email exists, real email";
}
else
{
    echo "email doesn't exist";
}


function isEmialExist($emailAddress)
{
    if (!filter_var($emailAddress, FILTER_VALIDATE_EMAIL)) {
     return false; //invalid format
    }
    //now check if email really exist
    $postdata = http_build_query(array('api_key' => 'YOUR_API_KEY', 'email' => $emailAddress ));
    $url = "https://email-validator.com/api/v1.0/json";
    $opts = array('http' => array( 'method'  => 'POST', 'header'  => 'Content-Type: application/x-www-form-urlencoded', 'content' => $postdata ));
    
    $context  = stream_context_create($opts);
    $result = file_get_contents($url, false, $context);
    $data = json_decode($result, false);
    return $data->is_exists;
}

你可以在这里找到更多详细信息。 https://email-validator.com/tutorial

-1

上述正则表达式有什么问题?
RFC822电子邮件地址标准非常宽松,因此很难找到一个简洁的正则表达式来捕获所有可能的有效电子邮件。事情变得复杂的原因是并不是每个邮件服务器/客户端都强制执行此标准,因此实际数据可能会出现问题。

虽然您可以猜测或强制执行特定格式,但编写临时表达式几乎可以保证您将拥有大量垃圾邮件地址或拒绝有效地址。

验证电子邮件的好的正则表达式是什么?
这是针对RFC进行验证的参考正则表达式,它在这里作为Perl模块实现,但也是O'Reilly的“Mastering Regular Expressions”的最终清单。

Mail::RFC822::Address


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接