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

标签 regex

这些年来我慢慢开发了一个regular expression正确验证大多数电子邮件地址,假设它们不使用 IP 地址作为服务器部分。

我在几个 PHP 程序中使用它,并且大多数时候它都能工作。然而,有时有人联系我,说使用它的网站遇到了问题,我最终不得不做出一些调整(最近我意识到我不允许使用四个字符 TLDs )。

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

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

最佳答案

fully RFC 822 compliant regex由于其长度而效率低下且晦涩难懂。幸运的是,RFC 822 已被取代两次,当前的电子邮件地址规范是 RFC 5322 。 RFC 5322 提供了一个正则表达式,只要研究几分钟就可以理解,并且对于实际使用来说足够高效。

可以在页面顶部 http://emailregex.com/ 找到一个符合 RFC 5322 的正则表达式。但使用了互联网上流传的 IP 地址模式,该模式存在一个错误,该错误允许使用 00 表示点分隔地址中的任何无符号字节十进制值,这是非法的。其余部分似乎与 RFC 5322 语法一致,并使用 grep -Po 通过了多项测试,包括域名、IP 地址、错误地址以及带引号和不带引号的帐户名。

纠正 IP 模式中的 00 错误,我们获得了一个有效且相当快的正则表达式。 (为实际代码抓取渲染版本,而不是 Markdown 版本。)

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

或者:

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

这里是diagramfinite state machine对于上面的正则表达式,它比正则表达式本身更清晰 enter image description here

Perl 和 PCRE(例如在 PHP 中使用的正则表达式库)中更复杂的模式可以 correctly parse RFC 5322 without a hitch 。 Python 和 C# 也可以做到这一点,但它们使用与前两者不同的语法。但是,如果您被迫使用众多功能较弱的模式匹配语言之一,那么最好使用真正的解析器。

了解根据 RFC 进行验证绝对不会告诉您该地址是否确实存在于所提供的域中,或者输入该地址的人是否是其真正的所有者,了解这一点也很重要。人们一直以这种方式将其他人注册到邮件列表。解决这个问题需要一种更奇特的验证,包括向该地址发送一条消息,其中包含一个确认 token ,该 token 应在与该地址相同的网页上输入。

确认 token 是了解您获得输入者地址的唯一方法。这就是为什么现在大多数邮件列表都使用该机制来确认注册。毕竟,任何人都可以写下 president@whitehouse.gov,这甚至会被解析为合法,但不太可能是另一端的人。

对于 PHP,您不应该使用 Validate an E-Mail Address with PHP, the Right Way 中给出的模式。我从中引用:

There is some danger that common usage and widespread sloppy coding will establish a de facto standard for e-mail addresses that is more restrictive than the recorded formal standard.

这并不比所有其他非 RFC 模式更好。它甚至不够智能,无法处理 RFC 822 ,更不用说 RFC 5322 了。This one然而,是。

如果你想要变得花哨和迂腐,implement a complete state engine 。正则表达式只能充当基本过滤器。正则表达式的问题在于,从用户的角度来看,告诉某人他们完全有效的电子邮件地址无效(误报),因为您的正则表达式无法处理它,这是粗鲁和不礼貌的。用于此目的的状态引擎可以验证甚至纠正电子邮件地址,否则这些地址在根据每个 RFC 分解电子邮件地址时会被视为无效。这可能会带来更愉快的体验,例如

The specified e-mail address 'myemail@address,com' is invalid. Did you mean 'myemail@address.com'?

另请参阅Validating Email Addresses ,包括评论。或Comparing E-mail Address Validating Regular Expressions .

Regular expression visualization

Debuggex Demo

关于regex - 如何使用正则表达式验证电子邮件地址?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55960464/

相关文章:

sql - 我可以通过给出 regexp_substr 的查询来创建选择组吗?

小写字母或句点后跟大写字母的正则表达式

javascript - 将文本拆分为 block (Javascript、正则表达式)

regex - 如果文件或目录存在,则 RewriteCond 跳过规则

javascript - 正则表达式验证范围内的日期年份

regex - IIS Url 重写 : Add Trailing Slash, 保留 anchor 和查询字符串

regex - 为字符串列表创建正则表达式

c# - 正则表达式匹配未完成

regex - 使用 wingrep 搜索 ip 地址

java - 如何在正则表达式中定义开关案例?