最有效的方法来检查$ string是否以perl中的$ needle开头

Ste*_*las 24 perl performance string-matching

鉴于两个字符串变量$string$needlein perl,什么是检查是否$string开始的最有效方法$needle.

  • $string =~ /^\Q$needle\E/ 是我能想到的最接近的匹配,它做了所需要的但是效率最低(到目前为止)我尝试过的解决方案.
  • index($string, $needle) == 0对某些值有效并且相对有效$string,$needle但不必要地在其他位置搜索针(如果在开始时没有找到).
  • substr($string, 0, length($needle)) eq $needle 应该是非常简单和有效的,但在我的几个测试中,大多数测试并不比前一个测试更有效.

是否有规范的方法可以做到这一点perl,我不知道或以任何方式优化任何上述解决方案?

(在我的特定用例中,$string并且$needle在每次运行中将会有所不同,因此预编译正则表达式不是一种选择).


如何衡量给定解决方案性能的示例(此处来自POSIX sh):

string='somewhat not so longish string' needle='somew'
time perl -e '
  ($n,$string,$needle) = @ARGV;
  for ($i=0;$i<$n;$i++) {

    index($string, $needle) == 0

  }' 10000000 "$string" "$needle"
Run Code Online (Sandbox Code Playgroud)

使用这些值,使用perl 5.14.2 index()substr()+eq使用此系统更好,但是:

string="aaaaabaaaaabaaaaabaaaaabaaaaabaaaaab" needle="aaaaaa"
Run Code Online (Sandbox Code Playgroud)

那是相反的.

Sue*_*mme 19

这有多重要,真的吗?我做了很多基准测试,index每次迭代的平均方法为0.68微秒; 正则表达式方法1.14μs; 该substr方法0.16μs.即使是我最糟糕的场景(2250-char字符串相同),index耗时2.4μs,正则表达式耗时5.7μs,substr耗时0.5μs.

我的建议是编写一个库例程:

sub begins_with
{
    return substr($_[0], 0, length($_[1])) eq $_[1];
}
Run Code Online (Sandbox Code Playgroud)

并将优化工作重点放在其他地方

更新:基于对上述"最坏情况"情况的批评,我运行了一组新的基准测试,其中包含一个20,000字符随机生成的字符串,将其与自身进行比较,并与仅在最后一个字节中不同的字符串进行比较.

对于如此长的字符串,正则表达式解决方案是迄今为止最差的(20,000字符的正则表达式是地狱):匹配成功为105μs,匹配失败为100μs.

indexsubstr解决方案仍然相当快.index成功/失败substr为11.83μs/11.86μs ,为4.09μs/4.15μs.将代码移动到单独的函数中添加约0.222±0.05μs.

基准代码见:http://codepaste.net/2k1y8e

我不知道@Sphane的数据的特征,但我的建议是立场.

  • “这真的有多重要吗?” 足以让OP提出问题并让你编写基准。这个开头问题除了让OP提出问题之外没有任何目的,并且与答案的其余部分相冲突。编写库例程的建议与问题无关,并且实际上支持该问题,因为库例程应该努力提高效率。最有效的实现是“rindex($_[0], $_[1], 0) == 0”,并且“rindex”的这种不寻常用法可以与解释它的注释一起隐藏在库例程中。 (3认同)
  • 没用,@ikegami。我的基准案例中有一半是匹配,一半是匹配失败。 (2认同)
  • @ SueD.Nymme:您发布的答案的措辞暗示您的最坏情况测试仅匹配字符串。显然,“索引”的最坏情况是一个非常长的草堆,它在任何地方都不包含针,因此必须一直进行到底。不过,我同意您的结论:只需使用`substr`,因为我们已经证明了在通常情况下它并不慢。它应该有一个*更好的*最坏情况,这对于抵御DOS攻击(或意外减速)非常重要。 (2认同)
  • 您可以尝试重现它们,而不是简单地取消我的基准测试结果。 (2认同)

Gre*_*bin 7

另一个选择是将rindex位置设置为0,这意味着“从位置<= 0开始,在$ str中获取$ substr的索引”,即它仅检查$ substr是否为$ str的前缀:

> rindex "abc", "a", 0
0
> rindex "abc", "b", 0
-1
Run Code Online (Sandbox Code Playgroud)

  • 很好,谢谢。这是我不知道并且正在寻找的功能。对于问题中的两个测试用例,我得到了相似的时间,并且它比任何其他方法都快。 (2认同)