2011-09-23 56 views
7

这是一个两部分问题。假设你有一组可以在一个字符处分割的字符串(例如,'@'处的电子邮件地址或'。'处的文件名),这是在分割字符之前查找字符的最高性能方式?Ruby字符串搜索:这是更快的拆分或正则表达式?

my_string.split(char)[0] 

my_string[/regex/] 

问题的第二部分是什么,你如何写一个正则表达式字符的第一个实例之前得到的一切。下面的正则表达式在'。'之前找到某些字符。 (因为'。'不在模式中),但这是我找到解决方案的方法。

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

谢谢!

+5

我怀疑在处理电子邮件地址时会有明显的差异(除非您每秒处理数百万次......)。但你为什么不衡量自己并找出答案? –

回答

12

回答第一部分的最简单方法是,像往常一样,用您的真实数据进行基准测试。例如:

require 'benchmark' 
Benchmark.bm do |x| 
    x.report { 50000.times { a = '[email protected]'.split('@')[0] } } 
    x.report { 50000.times { a = '[email protected]'[/[^@]+/] } } 
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[/[^.]+/] 

如果你想要的一切,之前第一阶段,然后说:“一切直到一段时间”,而非“时发出的第一个块这些字符(恰好不包含句点)“。

+0

谢谢你,我不知道ruby有一个内置的基准测试工具。在我自己的测试中,我发现正则表达式也更快,只要第一个子字符串小于50个字符,然后分割更快。当然,正如前面提到的那样,用小套装你几乎看不出有什么不同。 – kreek

+1

@Kreek:这就是为什么你会喜欢这样,学习新的东西:)我认为最好先从代码中尽可能清楚地表达你的意图,然后担心如果真的存在问题时的性能。 –

+0

@ muistooshort是不是有缓存效果或页面错误? – Benjamin

4

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

定期sliceindex将比正则表达式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, '[email protected]' 
bench n, '[email protected]' 
bench n, '[email protected]' 
bench n, '[email protected]' 
bench n, '[email protected]omain.com' 
bench n, 'a'*254 + '@' + 'b'*253 # rfc limits 
bench n, 'a'*1000 + '@' + 'b'*1000 # for other string processing 

结果1.9.3p484:

[email protected] 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) 

[email protected] 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) 

[email protected] 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) 

[email protected]ously-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) 

[email protected]omain.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%,除了正则表达式分割它减慢甚至更多。