多年来,我慢慢地开发了一个正则表达式,它可以正确验证大多数电子邮件地址,假设它们不使用IP地址作为服务器部分。

我在几个PHP程序中使用它,而且大多数时候都可以使用。然而,不时有人与我联系,他们对使用它的网站有问题,我最终不得不做出一些调整(最近我意识到我不允许四个字符的TLD)。

你有或见过验证电子邮件的最佳正则表达式是什么?

我见过几种使用函数的解决方案,这些函数使用了几个较短的表达式,但我宁愿在简单函数中使用一个长的复杂表达式,而不是在更复杂的函数中使用几个短表达式。


当前回答

出于我的目的,我需要一种方法来提取显示名称(如果提供)。感谢上提供的其他答案和正则表达式https://emailregex.com/我提出了以下解决方案:

/^(?:([^<]*?)\s*<)?((?:[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])+)\]))>?$/gi

这与显示名称(=组1)+电子邮件地址(=组2)相匹配。

匹配示例:

john.doe@example.com
john.o'doe@example.com
John <john@doe.com>
<john@doe.com>
This is <john@127.0.0.1>

使用测试https://regex101.com/

当然,正如其他答案中提到的,还需要对显示名称和电子邮件地址的长度进行额外验证(不应超过320个UTF-8字节)。

其他回答

电子邮件正则表达式(RFC 5322)

(?im)^(?=.{1,64}@)(?:("[^"\\]*(?:\\.[^"\\]*)*"@)|((?:[0-9a-z](?:\.(?!\.)|[-!#\$%&'\*\+/=\?\^`\{\}\|~\w])*)?[0-9a-z]@))(?=.{1,255}$)(?:(\[(?:\d{1,3}\.){3}\d{1,3}\])|((?:(?=.{1,63}\.)[0-9a-z][-\w]*[0-9a-z]*\.)+[a-z0-9][\-a-z0-9]{0,22}[a-z0-9])|((?=.{1,63}$)[0-9a-z][-\w]*))$

演示https://regex101.com/r/ObS3QZ/1

# (?im)^(?=.{1,64}@)(?:("[^"\\]*(?:\\.[^"\\]*)*"@)|((?:[0-9a-z](?:\.(?!\.)|[-!#\$%&'\*\+/=\?\^`\{\}\|~\w])*)?[0-9a-z]@))(?=.{1,255}$)(?:(\[(?:\d{1,3}\.){3}\d{1,3}\])|((?:(?=.{1,63}\.)[0-9a-z][-\w]*[0-9a-z]*\.)+[a-z0-9][\-a-z0-9]{0,22}[a-z0-9])|((?=.{1,63}$)[0-9a-z][-\w]*))$

# Note - remove all comments '(comments)' before running this regex
# Find  \([^)]*\)  replace with nothing

(?im)                                     # Case insensitive
^                                         # BOS

                                          # Local part
(?= .{1,64} @ )                           # 64 max chars
(?:
     (                                         # (1 start), Quoted
          " [^"\\]*
          (?: \\ . [^"\\]* )*
          "
          @
     )                                         # (1 end)
  |                                          # or,
     (                                         # (2 start), Non-quoted
          (?:
               [0-9a-z]
               (?:
                    \.
                    (?! \. )
                 |                                          # or,
                    [-!#\$%&'\*\+/=\?\^`\{\}\|~\w]
               )*
          )?
          [0-9a-z]
          @
     )                                         # (2 end)
)
                                          # Domain part
(?= .{1,255} $ )                          # 255 max chars
(?:
     (                                         # (3 start), IP
          \[
          (?: \d{1,3} \. ){3}
          \d{1,3} \]
     )                                         # (3 end)
  |                                          # or,
     (                                         # (4 start), Others
          (?:                                       # Labels (63 max chars each)
               (?= .{1,63} \. )
               [0-9a-z] [-\w]* [0-9a-z]*
               \.
          )+
          [a-z0-9] [\-a-z0-9]{0,22} [a-z0-9]
     )                                         # (4 end)
  |                                          # or,
     (                                         # (5 start), Localdomain
          (?= .{1,63} $ )
          [0-9a-z] [-\w]*
     )                                         # (5 end)
)
$                                         # EOS

当您使用PHP编写时,我建议您使用PHP内置的电子邮件验证。

filter_var($value, FILTER_VALIDATE_EMAIL)

如果您运行的是低于5.3.6的PHP版本,请注意这个问题:错误#53091:当我试图过滤一个大于2264个字符的文本时出现崩溃

如果您想了解此内置验证如何工作的更多信息,请参阅此处:PHP的filter_var filter_VALIDATE_EMAIL实际工作吗?

虽然已经添加了非常详细的答案,但我认为对于一个正在寻找验证电子邮件地址或从Java字符串中获取所有电子邮件地址的简单方法的开发人员来说,这些答案已经足够复杂了。

public static boolean isEmailValid(@NonNull String email) {
    return android.util.Patterns.EMAIL_ADDRESS.matcher(email).matches();
}

就正则表达式而言,我总是使用这个正则表达式,这适用于我的问题。

"[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,6}"

如果您希望通过匹配电子邮件正则表达式从字符串中查找所有电子邮件地址。您可以在此链接中找到方法。

根据RFC 2821和RFC 2822,电子邮件地址的本地部分可以使用以下任意ASCII字符:

大写和小写字母数字0到9字符!#$%&'*+-/=^_`{|}~字符“.”,前提是它不是本地部分中的第一个或最后一个字符。

比赛:

一个&d@somedomain.com一个*d@somedomain.com一个/d@somedomain.com

不匹配项:

.abc@somedomain.comabc.@somedomain.coma>b@somedomain.com

对于符合RFC 2821和2822的,可以使用:

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

电子邮件-符合RFC 2821、2822

没有一个是真正有用的。我在回答“是否有用于电子邮件地址验证的PHP库?”时讨论了一些问题?,它也在电子邮件地址的正则表达式识别难吗?中讨论?。

简而言之,不要期望一个可用的正则表达式能够完成正确的工作。最好的正则表达式将验证语法,而不是电子邮件的有效性(jhohn@example.com是正确的,但它可能会反弹…)。