javascript - 与 JavaScript 相比,正则表达式在 Ruby 中表现不佳

标签 javascript ruby-on-rails ruby regex

最近,我开始使用 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 中要快得多的原因。

引用:

JQuery Validation Plugin Source

Sample form with jQuery email validation

最佳答案

不知道为什么 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/

相关文章:

javascript - 如何安排 IE 页面重新加载

javascript - 移动设备 - iOS - Safari - window.outerHeight 返回 0

ruby-on-rails - 回形针视频倾斜(不保持纵横比)

ruby-on-rails - 没有 rails 的 ERB 中的 yield

ruby-on-rails - 带有 Devise 和 rspec : Warden test helpers unreliable 的 Rails 3

javascript - 有趣的 JavaScript 继承模式

javascript - 使用 jquery 制作网格 - 代码不完整

ruby-on-rails - 如何在 text_field 中设置默认值?

ruby-on-rails - w 设计,如何允许登录用户以其他用户身份登录

ruby - 如何在ruby中找到不是当前文件的文件路径