最近,我开始在我的Rails模型中使用JQuery validation插件中的电子邮件验证正则表达式。
EMAIL_REGEXP=/^((([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])))$/i
"aaaaa.bbbbbb.ccccc.ddddd@gmail.com".match EMAIL_REGEXP # returns immidiately
"aaaaa.bbbbbb.ccccc.ddddd@gmail".match EMAIL_REGEXP # takes a long time
当无效的电子邮件有多个点分隔的标记时,正则表达式需要很长时间(例如:first.middle.last@gmail)。相同的表达式works without JavaScript中任何明显的延迟。
为什么Ruby和JavaScript正则表达式解析器之间的性能存在这样的差异?我能做些什么来改善响应时间吗?
我在Ruby 1.8.7上。我在Ruby 1.9.2上看不到同样的问题。
注意
我知道reg-exp很长。由于它被jQuery使用,我想到了使用它。我可以随时将其更改为更简单的正则表达式,如here所示。我的问题主要是找出JS中相同正则表达式更快的原因。
参考:
答案 0 :(得分:1)
问题可能在于你的Regexp包含一个贪婪的量词,所以Ruby和那些量词需要尝试检查所有组合。解决方案可能是使用Possessive Quantifiers
,因此查找速度会更快,但会改变正则表达式,因此某些字符串将不再匹配。简短示例(来自维基百科):
'aaaaaaaaaaaaaaaaaaaaaaaaa' =~ /(a+a+)/ => match
'aaaaaaaaaaaaaaaaaaaaaaaaa' =~ /(a++a+)/ => not match
差异在于查找过程,在贪婪量词引擎中,如果没有匹配则尝试回顾,在占有量词引擎的情况下永远不会回头。
答案 1 :(得分:1)
不知道为什么来自1.8.7的正则表达式解析器比来自JS或Oniguruma的1.9.2中的正则解析器要慢得多,但可能这个特殊的正则表达式可以从包含@
的前缀中受益。像这样的原子组符号:
EMAIL_REGEXP = /
^
(?>(( # atomic group start
([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)
)
)
@) # atomic group end
(
(
([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])
)
)
$
/xi
puts "aaaaa.bbbbbb.ccccc.ddddd@gmail.com".match EMAIL_REGEXP # returns immediately
puts "aaaaa.bbbbbb.ccccc.ddddd@gmail".match EMAIL_REGEXP # takes a long time
在这种情况下,Atomic组应该阻止解析器在匹配@
符号后面的部分失败时返回到字符串的第一部分。它可以显着提高速度。虽然,我并非100%确定它不会破坏正则表达式逻辑,所以我对任何评论表示感谢。
另一件事是使用非捕获组,一般情况下,当您不需要对组进行反向引用时,它们应该更快,但在这种情况下它们不会给出明显的改进。