最近,我开始使用 JQuery validation 中的电子邮件验证正则表达式我的 Rails 模型中的插件。
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 上没有看到同样的问题。
注意
我知道正则表达式很长。既然是jQuery用的,我就想到用它。我总是可以将它改回更简单的正则表达式,如图所示 here .我的问题主要是找出为什么相同的正则表达式在 JS 中要快得多的原因。
引用:
最佳答案
不知道为什么 1.8.7 的正则表达式解析器比 1.9.2 的 JS 或 Oniguruma 的正则表达式解析器慢得多,但也许这个特定的正则表达式可以从包含 @
的前缀中受益> 带有这样原子团的符号:
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
这种情况下的原子组应该防止解析器在匹配 @
符号后的部分失败时返回到字符串的第一部分。它提供了显着的加速。不过,我不能 100% 确定它不会破坏正则表达式逻辑,所以我很感激任何评论。
另一件事是使用非捕获组,当您不需要对组进行反向引用时,它通常应该更快,但在这种情况下它们没有提供任何明显的改进。
关于javascript - 与 JavaScript 相比,正则表达式在 Ruby 中表现不佳,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8305947/