14

文字列内のFとTの数を数える次のPerlスクリプトがあります。

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

カウントを取得する(つまり、2行目と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;
    },
};
        レートtrm
     レートmtr
m 108 / s---99%
tr 8118 / s 7440%-

32WindowsXP上のActiveStatePerl5.10.1.1006を使用。

違いはスターカーのようです

C:\ Temp> c:\ opt \ skeleton-5.12.1 \ perl \ bin \ perl.exe t.pl
      レートmtr
m 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

しかし、それはまだ2行です。それを短くすることができる別の奇妙なトリック:

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

「()=」は「m」をリストコンテキストに強制します。N個の要素を持つリストをゼロ変数のリストに割り当てても、実際には何も起こりません。ただし、この代入式がスカラーコンテキスト($ ft_count = ...)で使用される場合、右の "="演算子は、右側から要素の数を返します。これはまさに必要な数です。

これは最初に遭遇したときは信じられないほど奇妙ですが、「=()=」イディオムは「リストコンテキストで評価してからリストのサイズを取得する」ために知っておくと便利なPerlのトリックです。

注:大きな文字列を処理するときに、これらのどれがより効率的であるかについてのデータはありません。実際、その場合は元のコードが最適だと思います。

于 2010-09-28T14:41:39.537 に答える
0

次のように、2、3、4行目を1つに組み合わせることができます。

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