Ruby字符串搜索:哪个更快拆分或正则表达式?

时间:2011-09-23 18:45:07

标签: ruby regex

这是一个两部分问题。假设您有一个字符串数组,可以在一个字符处拆分(例如,电子邮件地址为'@'或文件名为'。'),这是在拆分字符之前找到字符的最佳方式吗?

my_string.split(char)[0]

my_string[/regex/]

问题的第二部分是你如何编写一个正则表达式来获取角色的第一个实例之前的所有内容。下面的正则表达式在'。'之前找到某些字符。 (因为'。'不在模式中)但这是我找到解决方案的hacky方法。

my_string[/[A-Za-z0-9\_-]+/]

谢谢!

2 个答案:

答案 0 :(得分:12)

回答第一部分的最简单方法是一如既往地将其与您的真实数据进行对比。例如:

require 'benchmark'
Benchmark.bm do |x|
    x.report { 50000.times { a = 'a@b.c'.split('@')[0] } }
    x.report { 50000.times { a = 'a@b.c'[/[^@]+/] } }
end

说(在我的设置上):

      user     system      total        real
  0.130000   0.010000   0.140000 (  0.130946)
  0.090000   0.000000   0.090000 (  0.096260)

因此正则表达式解决方案看起来要快一点,但即使有50 000次迭代,差异也几乎不可察觉。 OTOH,正则表达式解决方案准确地说出你的意思(“在第一个@之前给我一切”),而split解决方案以稍微迂回的方式得到你想要的结果。

split方法可能更慢,因为它必须扫描整个字符串以将其拆分成片段,然后构建一个片段数组,最后提取数组的第一个元素并将其余部分抛弃;我不知道虚拟机是否足够聪明,无法识别它不需要构建阵列,因此只需要一些快速的猜测工作。

就你的第二个问题而言,说出你的意思:

my_string[/[^.]+/]

如果你想要在第一个时期之前的所有内容然后说“一切直到一段时间”而不是“由这些字符构成的第一个块(碰巧不包含句号)”。

答案 1 :(得分:4)

partition会比split更快,因为它在第一场比赛后不会继续检查。

slice的常规index将比正则表达式slice更快。

当匹配前字符串的部分变大时,正则表达式切片也会显着减慢。它变得比大约10个字符之后的原始分割慢,然后从那里变得更加糟糕。如果你有一个没有+*匹配的正则表达式,我认为它会更好一点。

require 'benchmark'
n=1000000

def bench n,email
  printf "\n%s %s times\n", email, n
  Benchmark.bm do |x|
      x.report('split    ') do n.times{ email.split('@')[0]  } end
      x.report('partition') do n.times{ email.partition('@').first  } end
      x.report('slice reg') do n.times{ email[/[^@]+/]  } end
      x.report('slice ind') do n.times{ email[0,email.index('@')]  } end
  end
end


bench n, 'a@be.pl'
bench n, 'some_name@regulardomain.com'
bench n, 'some_really_long_long_email_name@regulardomain.com'
bench n, 'some_name@rediculously-extra-long-silly-domain.com'
bench n, 'some_really_long_long_email_name@rediculously-extra-long-silly-domain.com'
bench n, 'a'*254 + '@' + 'b'*253    # rfc limits
bench n, 'a'*1000 + '@' + 'b'*1000  # for other string processing

结果1.9.3p484:

a@be.pl 1000000 times
       user     system      total        real
split      0.405000   0.000000   0.405000 (  0.410023)
partition  0.375000   0.000000   0.375000 (  0.368021)
slice reg  0.359000   0.000000   0.359000 (  0.357020)
slice ind  0.312000   0.000000   0.312000 (  0.309018)

some_name@regulardomain.com 1000000 times
       user     system      total        real
split      0.421000   0.000000   0.421000 (  0.432025)
partition  0.374000   0.000000   0.374000 (  0.379021)
slice reg  0.421000   0.000000   0.421000 (  0.411024)
slice ind  0.312000   0.000000   0.312000 (  0.315018)

some_really_long_long_email_name@regulardomain.com 1000000 times
       user     system      total        real
split      0.593000   0.000000   0.593000 (  0.589034)
partition  0.531000   0.000000   0.531000 (  0.529030)
slice reg  0.764000   0.000000   0.764000 (  0.771044)
slice ind  0.484000   0.000000   0.484000 (  0.478027)

some_name@rediculously-extra-long-silly-domain.com 1000000 times
       user     system      total        real
split      0.483000   0.000000   0.483000 (  0.481028)
partition  0.390000   0.016000   0.406000 (  0.404023)
slice reg  0.406000   0.000000   0.406000 (  0.411024)
slice ind  0.312000   0.000000   0.312000 (  0.344020)

some_really_long_long_email_name@rediculously-extra-long-silly-domain.com 1000000 times
       user     system      total        real
split      0.639000   0.000000   0.639000 (  0.646037)
partition  0.609000   0.000000   0.609000 (  0.596034)
slice reg  0.764000   0.000000   0.764000 (  0.773044)
slice ind  0.499000   0.000000   0.499000 (  0.491028)

a<254>@b<253> 1000000 times
       user     system      total        real
split      0.952000   0.000000   0.952000 (  0.960055)
partition  0.733000   0.000000   0.733000 (  0.731042)
slice reg  3.432000   0.000000   3.432000 (  3.429196)
slice ind  0.624000   0.000000   0.624000 (  0.625036)

a<1000>@b<1000> 1000000 times
       user     system      total        real
split      1.888000   0.000000   1.888000 (  1.892108)
partition  1.170000   0.016000   1.186000 (  1.188068)
slice reg 12.885000   0.000000  12.885000 ( 12.914739)
slice ind  1.108000   0.000000   1.108000 (  1.097063)

2.1.3p242保持大约相同的%差异,但在所有事情上都快了大约10-30%,除了正则表达式分裂,它减慢甚至更多。