【问题标题】:Unanchored substring searching: index vs regex?未锚定的子字符串搜索:索引与正则表达式?
【发布时间】:2015-06-09 23:09:08
【问题描述】:

我正在编写一些需要进行大量字符串匹配的 Perl 脚本。 例如:

my $str1 = "this is a test string";
my $str2 = "test";

查看 $str1 是否包含 $str2 - 我发现有两种方法:

方法一: 使用索引函数:

if ( index($str1, $str2) != -1 ) { .... }

方法 2: 使用正则表达式:

if( $str1 =~ /$str2/ ) { .... }

哪个更好?我们什么时候应该使用它们中的每一个?

【问题讨论】:

  • 为简单起见,我们假设字符串不包含正则表达式元字符(与我的用例一样)。这种情况下的答案是什么?
  • 您通常不会在字符串中的 anywhere 中寻找匹配项。在您的示例中,您可能希望 this is a test string 匹配,但您可能不想匹配 I am a Protestant。事实上,在任何地方寻找匹配项(无论是index 还是未锚定的正则表达式)是一个常见的逻辑错误。
  • 我认为正则表达式会尝试优化表达式中第一个字母的位置。两种方式都可能更快,更好地进行基准测试。而且我认为正则表达式允许您从上一场比赛停止的地方继续寻找下一场比赛。但是,它可能是 index 允许您设置起始位置(不记得)。
  • index($str1, $str2) != -1的等价物其实是$str1 =~ /\Q$str2/

标签: regex perl


【解决方案1】:

这是基准测试的结果:

use Benchmark qw(:all) ;
my $count = -1;
my $str1 = "this is a test string";
my $str2 = "test";
my $str3 = qr/test/;

cmpthese($count, {
    'type1' => sub { if ( index($str1, $str2) != -1 ) { 1 } },
    'type2' => sub { if( $str1 =~ $str3 ) { 1 } },
});

结果(发生匹配时):

           Rate type2 type1
type2 1747627/s    --  -70%
type1 5770465/s  230%    --

为了能够得出结论,请测试 not 是否匹配:

my $str2 = "text";
my $str3 = qr/text/;

结果(未发生匹配时):

           Rate type2 type1
type2 1857295/s    --  -67%
type1 5560630/s  199%    --

结论:

index 函数比正则表达式匹配要快得多。

【讨论】:

  • 除了基准之外,我想了解为什么这样的简单匹配要快得多。好的,有编译时间,但对于这种情况通常只执行一次。我会知道算法方面的差异。
  • @Nuxwin:我无法为您提供此类信息,但在运行 B::DebugB::Concise 模块时您将获得有用的信息。见:perldoc.perl.org/index-modules-B.html
【解决方案2】:

当我看到使用index 的代码时,我通常会在index 中看到indexindex 中,等等。还有更多分支:“如果找到,请查找this;否则由于找不到,请寻找那个。"几乎总是一个单一的正则表达式会起作用。所以,对我来说,我几乎总是使用正则表达式,除非有特定原因我想使用 index

不幸的是,我遇到的大多数程序员都没有很好地阅读正则表达式,因此为了可维护性,应该比我更多地使用 index 方法。

【讨论】:

  • 当阅读作者的昵称@‌sin 而不是@sln 时,上面的评论更有魅力。谢谢,无衬线字体!
【解决方案3】:

如果您需要子字符串匹配,请使用index。如果您需要正则表达式匹配(正则表达式元字符具有特殊含义),请使用=~。子字符串匹配通常更快,但是 Perl 中的正则表达式已经得到了很好的优化,简单的正则表达式匹配可以非常快。自己做基准测试。

从 Perl 5.6 开始,Perl 足够聪明,可以重新编译 $str =~ /$str2/ 中的正则表达式,如果 $str2 自上次编译后发生了变化。要完全控制编译正则表达式的时间,请使用qr/$str2/。请参阅 Does the 'o' modifier for Perl regular expressions still provide any benefit? 了解 q/.../o(已过时)和 qr/.../(大部分时间不需要,但可能很有用)。

【讨论】:

  • 如果$str2 不改变,模式就不会被重新编译,所以/o 没用。如果$str2 确实发生了变化,则需要重新编译模式,所以/o 是错误的。 /o 充其量是没用的,所以不,不要使用/o
  • 我想强调的是,@ikegami said 不仅适用于这种情况,而且几乎适用于所有情况。请参阅this question 了解更多信息。
  • 更新了我对/o的回答。
猜你喜欢
  • 2019-10-17
  • 2011-07-28
  • 1970-01-01
  • 2014-09-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多