如何计算Perl中的字符?

Dan*_*age 12 regex perl charactercount

我有以下Perl脚本计算字符串中的Fs和Ts的数量:

my $str = "GGGFFEEIIEETTGGG";
my $ft_count = 0;
$ft_count++ while($str =~ m/[FT]/g);
print "$ft_count\n";
Run Code Online (Sandbox Code Playgroud)

是否有更简洁的方法来计算(换句话说,结合第2和第3行)?

Sin*_*nür 25

my $ft_count = $str =~ tr/FT//;
Run Code Online (Sandbox Code Playgroud)

perlop.

如果REPLACEMENTLIST为空,则复制SEARCHLIST.后者对于计算类中的字符很有用...

  $cnt = $sky =~ tr/*/*/;     # count the stars in $sky
  $cnt = tr/0-9//;            # count the digits in $_
Run Code Online (Sandbox Code Playgroud)

这是一个基准:

use strict; use warnings;

use Benchmark qw( cmpthese );

my ($x, $y) = ("GGGFFEEIIEETTGGG" x 1000) x 2;

cmpthese -5, {
    'tr' => sub {
        my $cnt = $x =~ tr/FT//;
    },
    'm' => sub {
        my $cnt = ()= $y =~ m/[FT]/g;
    },
};
Run Code Online (Sandbox Code Playgroud)
        Rate     tr      m
     Rate     m    tr
m   108/s    --  -99%
tr 8118/s 7440%    --

使用32位Windows XP上的ActiveState Perl 5.10.1.1006.

差异似乎更加明显

C:\Temp> c:\opt\strawberry-5.12.1\perl\bin\perl.exe t.pl
      Rate      m     tr
m   88.8/s     --  -100%
tr 25507/s 28631%     --

  • 由于正则表达式匹配在标量上下文中,因此您的基准测试是让"m"案例因为找到第一个匹配而逃脱.如果我将该行修改为"my $ cnt =()= $ y = ~m/[FT]/g;",则"tr"比"m"(在我的Linux机器上)好大约3000%.顺便说一句,原始代码大约是"m"的两倍. (4认同)
  • 当然tr ///不是正则表达式所以*技术上*它没有回答具体问题:-)然而,它比使用正则表达式要好得多. (3认同)
  • @Sinan +1表示`tr ///`.我认为您的基准测试有一个错误.为了用regex计算替换,你需要一个插入列表上下文:`my $ cnt =()= $ y = ~m/[FT]/g;`.当你以这种方式运行时,`tr ///`比`m //`快得多.我也在ActivePerl下的v5.10上. (3认同)
  • @SinanÜnür这就是为什么在基准测试之前有一个测试部分是个好主意.我通常将要测试的lambda填充到哈希中,遍历哈希打印其返回值,然后执行基准测试.如果任何值不同,那么我知道我有一个糟糕的基准. (2认同)

Cha*_*ens 8

是的,您可以使用CountOf secret操作符:

my $ft_count = ()= $str =~ m/[FT]/g;
Run Code Online (Sandbox Code Playgroud)

  • 也称为goatse运算符;)`=()=` (2认同)

asc*_*ler 8

当"m"运算符在列表上下文中执行/ g标志AND时,它返回匹配的子字符串列表.所以另一种方法是:

my @ft_matches = $str =~ m/[FT]/g;
my $ft_count = @ft_matches; # count elements of array
Run Code Online (Sandbox Code Playgroud)

但那还是两行.另一个可以缩短它的怪异技巧:

my $ft_count = () = $str =~ m/[FT]/g;
Run Code Online (Sandbox Code Playgroud)

"()="强制"m"在列表上下文中.将具有N个元素的列表分配给零变量列表实际上并不执行任何操作.但是当这个赋值表达式在标量上下文中使用时($ ft_count = ...),右边的"="运算符会从右侧返回元素的数量- 正是你想要的.

这在第一次遇到时非常奇怪,但是"=()="成语是一个有用的Perl技巧,因为"在列表上下文中进行评估,然后得到列表的大小".

注意:我没有关于在处理大字符串时哪些更有效的数据.事实上,我怀疑你的原始代码在这种情况下可能是最好的.