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

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

my_string.split(char)[0] 

要么

 my_string[/regex/] 

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

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

谢谢!

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

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

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

 my_string[/[^.]+/] 

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

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

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

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

 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%,除了regexp分裂,它减速甚至更多。