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

问题描述:

我们都知道正确验证电子邮件的正则表达式是quite complicated。然而,jQuery的验证插件具有更短的正则表达式(贡献的Scott Gonzalez,跨越只有几行:为什么jQuery的电子邮件验证正则表达式如此简单?

/^((([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])))\.?$/ 

为什么会这样“简单”相比,更知名的怪物?有一种情况下,一个正则表达式会失败,另一个会成功(这些情况是否是有效或无效的电子邮件)?

+12

简单不是我将用于该正则表达式的单词;) – JaredPar 2010-12-01 02:02:43

+4

* Ahem *简单?如果这个正则表达式很简单,那么你会把什么归类为复杂的? – Alex 2010-12-01 02:03:34

+0

谈论踩在只写语言的领土... – Serguei 2010-12-01 02:05:16

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

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

我写了正在起草和RFC 5322不存在的正则表达式。如果您查看RFC的编写顺序,您将注意到在写入Internet邮件格式后,IRI和URI的定义发生了变化。这意味着RFC 2822不支持当前的IRI定义。不幸的是,这不是一个简单的任务,只需要替换定义,所以我必须从哪个RFC中选择使用哪些定义。我也选择了要删除的内容(如对评论的支持)。

该正则表达式并不完全是手写的。虽然我手动编写了正则表达式的每个部分,但我编写了“胶水”。来自RFC的每个定义都存储在一个变量中,化合物定义利用存储简单定义的变量(@Walf:这就是为什么有这么多子模式和ors)。

使事情复杂化,在jQuery验证插件中使用的正则表达式的版本进一步修改,以解决spec-valid地址和用户期望有效地址之间的差异。我不记得我做了什么修改。我答应JörnZaefferer(验证插件的作者),我会写一个更新的脚本来生成正则表达式。新脚本将允许您指定您所做和不想支持的选项(必需的顶级域名,特定的顶级域名,IPv6,注释,过时的定义,引用的本地名称等)。那是5年前。我开始了一次,但从未完成。也许有一天我会。我至今托管在GitHub上:https://github.com/scottgonzalez/regex-builder

如果你想为验证邮件地址的正则表达式,我建议这包括在HTML5 specification以下的正则表达式:

/^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-][email protected][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先进的美国从阿帕网到互联网ARPA,这是不完全的电流。互联网在过去三十年取得了一些进展,并且这个RFC已经被两次取代。我希望看到遵循最新标准的新工作。


UPDATE:

有朋友问我,为什么HTML5正则表达式不支持UTF-8。我从来没有向Hixie询问过这件事,但我认为这是原因:尽管一些TLD在2000年开始支持IDN(国际域名),并且在2005年编写了RFC 3987(IRI),但在2008年编写RFC 5322它仅将33-90和94-126范围内的字符列为有效的dtext(允许在域文字中使用的字符)。 HTML5基于RFC 5322,因此没有UTF-8支持。 RFC 5322没有考虑IDN,这似乎很奇怪,但即使在2008年,IDN并没有实际可用,但它是毫无价值的。直到2010年,ICANN才批准了第一批IDN。然而,即使在今天,如果你想使用IDN,你几乎需要使用Punycode彻底销毁你的域名,如果你真的想让电子邮件和DNS等全球工作。

更新2:

更新HTML5正则表达式相匹配的更新的规范,该规范改变标签长度范围从255个字符到63个字符,如在RFC 1034 section 3.5指定。

这看起来不正确:Unicode是什么?哪一个RFC可以证实这一点?

请参阅this answer以获得正确的RFC5322验证正则表达式。