【问题标题】:Most efficient way to check if $string starts with $needle in perl在 perl 中检查 $string 是否以 $needle 开头的最有效方法
【发布时间】:2015-10-21 20:29:33
【问题描述】:

给定perl 中的两个字符串变量$string$needle,检查$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"

有了这些值,index() 在这个带有 perl 5.14.2 的系统中的性能优于 substr()+eq,但是:

string="aaaaabaaaaabaaaaabaaaaabaaaaabaaaaab" needle="aaaaaa"

反过来了。

【问题讨论】:

  • 不同版本的 Perl 会在这里产生影响,我建议添加您用于反馈或重用的基准代码。
  • @Ashley,好点,更新了。
  • 也许你会写String::MoreUtils::XS
  • 您是否对脚本进行了分析以确认确实需要这种微优化?
  • 仅供参考,您应该在任何时候使用 Benchmark module 在 Perl 中进行基准测试。 /usr/bin/time 不一定会给你一个公平的比较。

标签: performance perl string-matching


【解决方案1】:
rindex $string, $substring, 0

$string 中搜索$substring 只有在$substring$string 的前缀时才有可能在 位置。示例:

> rindex "abc", "a", 0
0
> rindex "abc", "b", 0
-1

【讨论】:

  • 非常感谢。这是我不知道并且正在寻找的功能。对于问题中的两个测试用例,我得到了相似的时间安排,并且比这两种方法中的任何其他方法都快。
【解决方案2】:

这真的很重要吗?我做了一些基准测试,index 方法平均每次迭代需要 0.68 微秒;正则表达式方法1.14μs; substr 方法 0.16μs。即使是我的最坏情况(2250 个字符的字符串相等),index 需要 2.4μs,正则表达式需要 5.7μs,substr 需要 0.5μs。

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

sub begins_with
{
    return substr($_[0], 0, length($_[1])) eq $_[1];
}

并将您的优化工作集中在其他地方。

更新:基于对上述“最坏情况”场景的批评,我使用随机生成的 20,000 个字符的字符串运行了一组新的基准测试,将其与自身和仅在最后一个不同的字符串进行比较字节。

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

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

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

我不知道@Stephane 数据的特点,但我的建议是成立的。

【讨论】:

  • 对于早期的perls,您可能想要omit the return statement
  • 不是没用的,@ikegami。我的基准案例中有一半是匹配的,一半是匹配失败的。
  • @SueD.Nymme:您发布的答案的措辞暗示您的最坏情况测试仅匹配字符串。显然,index 的最坏情况是一个极长的干草堆,任何地方都没有包含针头,因此它必须一直检查到最后。不过,我同意你的结论:只需使用substr,因为我们已经证明它在常见情况下并不慢。它应该有一个好多更好的最坏情况,这对于抵抗 DOS 攻击(或意外减速)很重要。
  • 您可以尝试重现它们,而不是简单地忽略我的基准测试结果。
  • @PeterCordes,在字符串中找不到针的情况中,有些情况比其他情况更糟,例如问题中的最后一个示例,其中至少 111 个字节到字节的比较((6+5+4+3+2+1)*5+6) 需要长度为 34 的字符串和长度为 6 的针。(对于这个长度的字符串/针,它甚至可能是最坏的情况,这会在这里提出另一个有趣的问题)
猜你喜欢
  • 1970-01-01
  • 2019-07-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-04
  • 2019-09-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多