如何使用正则表达式验证电子邮件地址?

4125
多年来,我已经逐渐开发出一种正则表达式,可以正确验证大多数电子邮件地址(假设它们没有使用IP地址作为服务器部分)。我在几个PHP程序中使用它,大多数情况下都有效。但是,不时有人联系我,称使用该表达式的站点出现问题,我最近意识到我没有允许四个字符的TLDs,因此不得不进行一些调整。你认为验证电子邮件的最佳正则表达式是什么?我看过几种解决方案,它们使用函数,这些函数使用几个较短的表达式,但我宁愿在一个简单的函数中使用一个长且复杂的表达式,而不是在一个更复杂的函数中使用几个短的表达式。

10
可以验证 IDNA 格式是否正确的正则表达式太长了,无法在 StackExchange 中使用。(规范化的规则非常复杂,特别不适合使用正则表达式处理。) - Jasen
正则表达式可能是可变的,因为在某些情况下,电子邮件内容可能包含空格,而在其他情况下,则不能包含任何空格。 - Ṃųỻịgǻňạcểơửṩ
我建议您查看这篇文章:https://debounce.io/blog/articles/email-syntax-error-explained/ - Iman
显示剩余7条评论
80个回答

29

自从2010年5月起,互联网上存在非拉丁字符(如中文、阿拉伯、希腊、希伯来、西里尔等)的域名。所有人都必须更改使用的电子邮件正则表达式,因为这些字符肯定不包含在[a-z]/i\w之内。它们都会失败。

最好的验证电子邮件地址的方法仍然是实际发送一封电子邮件到目标地址以验证该地址。如果电子邮件地址是用户身份验证(注册/登录等)的一部分,则可以与用户激活系统完美结合。即发送一封电子邮件,其中包含具有唯一激活密钥的链接到指定的电子邮件地址,并仅允许在用户使用电子邮件中的链接激活新创建的帐户后登录。

如果正则表达式的目的仅是在UI中快速通知用户指定的电子邮件地址不符合正确的格式,请检查它是否基本匹配以下正则表达式:

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

就这么简单。你为什么要关心名称和域中使用的字符呢?输入有效的电子邮件地址是客户端的责任,而不是服务器的责任。即使客户端输入了语法上有效的电子邮件地址,例如 aa@bb.cc,这也不能保证它是合法的电子邮件地址。没有一个正则表达式可以覆盖所有情况。


5
我同意发送身份验证消息通常是这种情况下最好的方式,语法正确和有效并不相同。当我被迫在“确认”时将我的电子邮件地址输入两次时,我感到沮丧,好像我不能看一下我所输入的内容。无论如何,我只会将第一个复制到第二个,但这似乎越来越普遍了。 - PeteT
2
同意!但是我认为这个正则表达式无效,因为它允许在“@.”之后添加空格,例如test@test.ca com net被上述正则表达式视为有效电子邮件,而实际上应该是无效的。 - CB4

28

关于验证电子邮件地址的最全面评估,请参见此链接:“比较电子邮件地址验证正则表达式”。

这是当前用于参考的顶级表达式:

/^([\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

1
spoon16:那个链接并不正确。它声称无法找到验证电子邮件地址的完美模式,这显然是错误的。你可以找到,但必须确保你严格遵循RFC标准。而且你还要选择正确的RFC标准。 - tchrist
1
“最好的”现在无法使用Java正则表达式 - 即使正确转义和转换字符串。 - Eric Chen

25

HTML5规范建议使用简单的正则表达式来验证电子邮件地址:

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

我故意不遵守RFC 5322

注意:这个要求是故意违反 RFC 5322 的规定,该规定定义了一种电子邮件地址的语法,同时过于严格(在 @ 字符之前)、过于模糊(在 @ 字符之后)和太松散(允许注释、空格字符和引用字符串以用户大多数不熟悉的方式使用),在这里没有实际用途。

总长度也可以限制为254个字符,根据RFC 3696 errata 1690


2
最佳答案!这是w3推荐的链接:https://www.w3.org/TR/html5/forms.html#valid-e-mail-address 这个正则表达式被许多浏览器采用。 - Ryan Taylor
6
这绝对不是最好的答案!这个模式与这个完全无效的地址匹配:invalid@emailaddress。在使用它之前,我建议谨慎并进行大量测试! - Sheridan
2
example@localhost 是有效的,但对于真实世界的应用程序,您可能希望强制使用域扩展名,您只需要将最后的 * 更改为 + 即可实现此目的(将模式的该部分从 0+ 更改为 1+)。 - Mitch Satchwell
4
“invalid@emailaddress” 是一个有效的电子邮件地址,只是它并不存在。(同时,根据你的网络配置,它甚至可以在你的本地网络中传递。)而判断一个电子邮件地址是否存在的唯一方法就是发送一封电子邮件。 - awwright
1
如果有人想在 Perl 中使用上面的代码,尽管 HTML5 规范表示兼容,但实际上需要对 $ 进行转义(变成 \$),因为 $% 是 Perl 中的特殊变量,因此包含 $% 的地址将被拒绝。 - Ecuador
显示剩余3条评论

16

为了生动演示,以下的“monster”还不错,但它仍然不能正确识别所有语法上有效的电子邮件地址:它只识别嵌套评论最多四级。

这需要一个解析器来完成,但即使地址在语法上是有效的,也可能无法投递。有时你必须采用山地人方法:“嘿,你们看着点!”

// 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);

1
什么编程语言?C# - Peter Mortensen

12
根据官方标准RFC 2822,一个有效的电子邮件正则表达式为:
(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])
如果你想在Java中使用它,那么非常简单:
import java.util.regex.*;

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

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

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

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

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

2
你的正则表达式没有包含第一个大写字母,例如 Leonardo.davinci@gmail.com,这可能会让一些用户感到烦恼。请改用这个:``(?:[A-Za-z0-9!#$%&'+/=?^_{|}~-]+(?:\.[A-Za-z0-9!#$%&'*+/=?^_{|}~-]+)|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\[\x01-\x09\x0b\x0c\x0e-\x7f])")@(?:(?:a-z0-9?.)+a-z0-9?|[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-][a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\[\x01-\x09\x0b\x0c\x0e-\x7f])+)])。 - Kebab Krabby
@KebabKrabby 谢谢,麻烦您编辑答案,我会接受更改。 - AZ_
如果我在您的回答中添加该更改,它将不再是RFC 2822,因此我不确定是否正确。 - Kebab Krabby
2
@KebabKrabby:我猜我们需要在匹配选项中的某个地方应用大小写不敏感模式,而不是更改正则表达式本身。 - Thomas Weller

11
RFC 5322标准:
允许使用点-原子本地部分,引用字符串本地部分,废弃的(混合点-原子和引用字符串)本地部分,域名域,(IPv4、IPv6和IPv4-mapped IPv6地址)字面域名域以及(嵌套的)CFWS。
'/^(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){255,})(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){65,}@)((?>(?>(?>((?>(?>(?>\x0D\x0A)?[\t ])+|(?>[\t ]*\x0D\x0A)?[\t ]+)?)(\((?>(?2)(?>[\x01-\x08\x0B\x0C\x0E-\'*-\[\]-\x7F]|\\\[\x00-\x7F]|(?3)))*(?2)\)))+(?2))|(?2))?)([!#-\'*+\/-9=?^-~-]+|"(?>(?2)(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\x7F]))*(?2)")(?>(?1)\.(?1)(?4))*(?1)@(?!(?1)[a-z0-9-]{64,})(?1)(?>([a-z0-9](?>[a-z0-9-]*[a-z0-9])?)(?>(?1)\.(?!(?1)[a-z0-9-]{64,})(?1)(?5)){0,126}|\[(?:(?>IPv6:(?>([a-f0-9]{1,4})(?>:(?6)){7}|(?!(?:.*[a-f0-9][:\]]){8,})((?6)(?>:(?6)){0,6})?::(?7)?))|(?>(?>IPv6:(?>(?6)(?>:(?6)){5}:|(?!(?:.*[a-f0-9]:){6,})(?8)?::(?>((?6)(?>:(?6)){0,4}):)?))?(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?>\.(?9)){3}))\])(?1)$/isD'

RFC 5321标准: 允许使用点号-原子本地部分,引用字符串本地部分,域名域和(IPv4、IPv6和IPv4-mapped IPv6地址)域文字域。
'/^(?!(?>"?(?>\\\[ -~]|[^"])"?){255,})(?!"?(?>\\\[ -~]|[^"]){65,}"?@)(?>([!#-\'*+\/-9=?^-~-]+)(?>\.(?1))*|"(?>[ !#-\[\]-~]|\\\[ -~])*")@(?!.*[^.]{64,})(?>([a-z0-9](?>[a-z0-9-]*[a-z0-9])?)(?>\.(?2)){0,126}|\[(?:(?>IPv6:(?>([a-f0-9]{1,4})(?>:(?3)){7}|(?!(?:.*[a-f0-9][:\]]){8,})((?3)(?>:(?3)){0,6})?::(?4)?))|(?>(?>IPv6:(?>(?3)(?>:(?3)){5}:|(?!(?:.*[a-f0-9]:){6,})(?5)?::(?>((?3)(?>:(?3)){0,4}):)?))?(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?>\.(?6)){3}))\])$/iD'

基本:

允许使用点-原子本地部分和域名域(至少需要两个域名标签,TLD 限制为 2-6 个字母字符)。

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

1
那是什么鬼语言?我看到了一个 /D 标志,你用单引号引用它,但也使用斜杠来分隔模式?这不是 Perl,也不可能是 PCRE。因此,它是 PHP 吗?我相信这些是唯一允许像 (?1) 这样递归的三种语言。 - tchrist
1
这是PHP编写的,使用了PCRE。斜杠仅用于分隔特殊字符,如括号、方括号,当然还有斜杠和单引号。如果您不知道,/D标志可以防止在字符串末尾添加换行符,否则将允许它的存在。 - Michael

11

以下是我使用的PHP代码。在这里,我选择了“误报好过漏报”的解决方案,正如另一个评论者所宣布的那样,并考虑到保持响应时间和减少服务器负载的要求... 当大多数简单用户错误都可以被检测出来时,没有必要浪费服务器资源去使用正则表达式。如果您愿意,您可以随时通过发送测试电子邮件来进行后续跟进。

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

2
a) “浪费服务器资源”微不足道,但如果您愿意,可以使用JS在客户端完成。 b) 如果需要发送注册邮件,而用户输入了me@forgotthedotcom,那么您的“解决方案”将失败并且您会失去一个用户。 - johnjohn
2
依赖于JS验证,当JavaScript被禁用时会失败,这也不是最好的想法(顺便说一下)。 - auco
什么是假阳性?是拒绝了本应接受的电子邮件地址吗?还是接受了本不应接受的电子邮件地址? - Peter Mortensen

8

如果您可以接受空值(这不是无效的电子邮件),并且正在运行PHP 5.2+,我建议:

static public function checkEmail($email, $ignore_empty = false) {
    if($ignore_empty && (is_null($email) || $email == ''))
        return true;
    return filter_var($email, FILTER_VALIDATE_EMAIL);
}

1
请举一个具有空值的地址的例子?请通过编辑(更改)您的答案来回答,而不是在评论中回答(不要包含“Edit:”、“Update:”或类似内容 - 答案应该看起来像是今天写的)。 - Peter Mortensen

8

我已经使用了修改过的原始正则表达式一段时间了,它没有给我留下太多惊喜。 我之前从未在电子邮件中遇到过撇号,所以正则表达式不能验证该字符。它可以验证Jean+François@anydomain.museum试@例子.测试.مثال.آزمایشی,但不能验证对这些非字母数字字符的滥用.+@you.com

(?!^[.+&'_-]*@.*$)(^[_\w\d+&'-]+(\.[_\w\d+&'-]*)*@[\w\d-]+(\.[\w\d-]+)*\.(([\d]{1,3})|([\w]{2,}))$)

它支持IP地址you@192.168.1.1,但我还没有完善它以处理虚假的IP地址范围,如999.999.999.1它也支持超过三个字符的所有顶级域名,这可以阻止类似asdf@asdf.asdf的情况,我认为原始代码是让它通过的。 我被打败了,现在有太多超过3个字符的顶级域名
我知道原贴已经放弃了他的正则表达式,但这种模式仍然存在。

1
对于所有人:问题中的正则表达式已在2015年的第10个修订版中删除(大约7年后)。 - Peter Mortensen
1
不应该使用删除线。这就是修订历史记录的作用。如果某些内容不再有效,应将其删除。答案应该像今天刚写的一样。 - Peter Mortensen

8
奇怪的是你们“不能”允许四个字符的顶级域名。你禁止了人们使用.info和.name,而长度限制也阻止了.travel和.museum,但是它们确实比两个字符的顶级域名和三个字符的顶级域名更不常见。
你应该允许大写字母。电子邮件系统将规范化本地部分和域部分。
对于域部分的正则表达式,域名不能以“-”开头或以“-”结尾。破折号只能在中间停留。
如果您使用PEAR库,请查看它们的邮件功能(我忘记了确切的名称/库)。您可以通过调用一个函数来验证电子邮件地址,并根据RFC 822中的定义验证电子邮件地址。

3
RFC 822 过时了吗? - tchrist
1
Re ' "cannot" allow 4 characters TLDs': 你指的是什么? - Peter Mortensen

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