为什么jQuery的电子邮件验证正则表达式如此简单?

con*_*tor 8 regex email jquery

我们都知道正确验证电子邮件的正则表达式会非常复杂.但是,jQuery的验证插件有一个较短的正则表达式(由Scott Gonzalez提供),只有几行:

/^((([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])))\.?$/
Run Code Online (Sandbox Code Playgroud)

与更为人熟知的怪物相比,为什么这么"简单"?是否存在一个正则表达式失败而另一个正式成功的情况(案例是有效还是无效的电子邮件)?

Sco*_*lez 10

正则表达式是自定义组合:

  • RFC 2234 ABNF
  • RFC 2396 URI通用语法(由RFC 3986引用)
  • RFC 2616超文本传输​​协议 - HTTP/1.1
  • RFC 2822 Internet邮件格式
  • RFC 3987 IRI
  • RFC 3986 URI通用语法

当我正在起草Web Forms 2.0并且RFC 5322不存在时,我编写了正则表达式.如果查看RFC的编写顺序,您会注意到写入Internet消息格式后IRI和URI的定义已更改.这意味着RFC 2822不支持当前的IRI定义.不幸的是,这不仅仅是替换定义的简单任务,因此我必须从哪个RFC中选择使用哪些定义.我还选择了要删除的内容(例如支持评论).

正则表达式不是完全手写的.当我手动编写正则表达式的每个部分时,我编写了"胶水"脚本.RFC中的每个定义都存储在一个变量中,复合定义利用存储更简单定义的变量(@Walf:这就是为什么有这么多的子模式和ors).

为了使问题复杂化,jQuery Validation插件中使用的正则表达式版本进一步修改,以解决规范有效地址与用户对有效地址的期望之间的差异.我不记得我做了哪些修改.我向JörnZaefferer(验证插件的作者)承诺,我会编写一个更新的脚本来生成正则表达式.新脚本允许您指定您要做和不想支持的选项(所需的TLD,特定TLD,IPv6,注释,过时的定义,引用的本地名称等).那是5年前的事了.我开始了一次,但从未完成.也许有一天我会.我到目前为止在GitHub上托管:https://github.com/scottgonzalez/regex-builder

如果你想要一个用于验证电子邮件地址的正则表达式,我建议使用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 822.虽然RFC 822将我们从Arpanet推进到ARPA Internet非常棒,但这并不是最新的.互联网在过去三十年取得了一些进展,这个RFC已被取代两次.我想看看遵循最新标准的任何新工作.


更新:

一位朋友问我为什么HTML5正则表达式不支持UTF-8.我从来没有问过Hixie,但我认为这就是原因:尽管一些TLD在2000年开始支持IDN(国际域名),而RFC 3987(IRI)是在2005年编写的,当时RFC 5322是在2008年编写的.它仅将33-90和94-126范围内的字符列为有效dtext(允许在域文字中使用的字符).HTML5基于RFC 5322,因此没有UTF-8支持.RFC 5322并没有考虑到IDN,这似乎很奇怪,但即使在2008年的IDN实际上并不可用,它也是值得的.直到2010年,ICANN才批准了第一套IDN.但是,即使在今天如果你想使用IDN,如果你真的希望像电子邮件和DNS这样的东西在全球范围内运行,你几乎需要使用Punycode完全破坏你的域名.

更新2:

更新了HTML5正则表达式以匹配更新的规范,该规范将标签长度限制从255个字符更改为63个字符,如RFC 1034第3.5节中所述.