使用交替或字符类进行单字符匹配?

时间:2011-01-18 13:28:17

标签: regex perl

(注意:标题似乎并不清楚 - 如果有人可以改写,我就是全部用它!)

鉴于这个正则表达式:(.*_e\.txt),它匹配一些文件名,除了e之外,我还需要添加一些其他单字符后缀。我应该选择一个角色类还是应该使用替换? (或者这真的很重要吗?)

也就是说,以下哪两个似乎“更好”,为什么:

a)(.*(e|f|x)\.txt)

b)(.*[efx]\.txt)

3 个答案:

答案 0 :(得分:22)

使用[efx] - 这正是设计用于的字符类:匹配其中一个包含的字符。因此,它也是最易读和最短的解决方案。

我不知道它是否更快,但如果不是,我会非常惊讶。它绝对不会慢。

我的推理(没有编写过正则表达式引擎,所以这是纯粹的猜想):

正则表达式令牌[abc]将在正则表达式引擎的一个步骤中应用:“下一个字符是ab还是c?”

然而,

(a|b|c)告诉正则表达式引擎

  • 记住字符串中的当前位置,如有必要,可以回溯
  • 检查是否可以匹配a。如果是这样,成功。如果不是:
  • 检查是否可以匹配b。如果是这样,成功。如果不是:
  • 检查是否可以匹配c。如果是这样,成功。如果不是:
  • 放弃。

答案 1 :(得分:13)

这是一个基准:

根据tchrist评论更新,差异更显着

#!/usr/bin/perl
use strict;
use warnings;
use 5.10.1;
use Benchmark qw(:all);

my @l;
foreach(qw/b c d f g h j k l m n ñ p q r s t v w x z B C D F G H J K L M N ñ P Q R S T V W X Z/) {
    push @l, "abc$_.txt";
}

my $re1 = qr/^(.*(b|c|d|f|g|h|j|k|l|m|n|ñ|p|q|r|s|t|v|w|x|z)\.txt)$/;
my $re2 = qr/^(.*[bcdfghjklmnñpqrstvwxz]\.txt)$/;
my $cpt;

my $count = -3;
my $r = cmpthese($count, {
    'alternation' => sub {
        for(@l) {
            $cpt++ if $_ =~ $re1;
        }
    },
    'class' => sub {
        for(@l) {
            $cpt++ if $_ =~ $re2;
        }
    }
});

<强>结果:

              Rate alternation       class
alternation 2855/s          --        -50%
class       5677/s         99%          --

答案 2 :(得分:1)

对于一个角色,它将具有如此微小的差异,这无关紧要。 (除非你做了很多操作)

但是,为了便于阅读(并略微提高性能),您应该使用字符类方法。

有关更多信息 - 打开圆括号(会导致Perl开始回溯当前位置,因为您没有进一步的匹配,所以您真的不需要正则表达式。字符类不会这样做。