14

I have the following Perl script counting the number of Fs and Ts in a string:

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

Is there a more concise way to get the count (in other words, to combine line 2 and 3)?

4

4 回答 4

26
my $ft_count = $str =~ tr/FT//;

perlop

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

  $cnt = $sky =~ tr/*/*/;     # count the stars in $sky
  $cnt = tr/0-9//;            # count the digits in $_

这是一个基准:

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;
    },
};
        率 tr m
     速率 m tr
米 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
      速率 m tr
米 88.8/s -- -100%
tr 25507/s 28631% --
于 2010-09-28T14:30:30.547 回答
8

是的,您可以使用CountOf 秘密运算符

my $ft_count = ()= $str =~ m/[FT]/g;
于 2010-09-28T14:31:07.227 回答
8

当“m”运算符具有 /g 标志并且在列表上下文中执行时,它返回匹配子字符串的列表。所以另一种方法是:

my @ft_matches = $str =~ m/[FT]/g;
my $ft_count = @ft_matches; # count elements of array

但这仍然是两条线。另一个可以使它更短的奇怪技巧:

my $ft_count = () = $str =~ m/[FT]/g;

"() = 强制 "m" 在列表上下文中。将具有 N 个元素的列表分配给零变量列表实际上并没有做任何事情。但是,当在标量上下文中使用此赋值表达式时($ft_count = ...),右侧的“=”运算符会从其右侧返回元素的数量- 正是您想要的。

这在第一次遇到时非常奇怪,但是“=()=”成语是一个有用的 Perl 技巧,用于“在列表上下文中评估,然后获取列表的大小”。

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

于 2010-09-28T14:41:39.537 回答
0

您可以将第 2、3 和 4 行合并为一个,如下所示:

my $str = "GGGFFEEIIEETTGGG";
print $str =~ s/[FT]//g; #Output 4;
于 2010-09-28T14:37:25.467 回答