4

メッセージ内の文字の出現頻度を調べる Perl スクリプトを作成しています。これが私が従っているロジックです:

  • getc() を使用してメッセージから一度に 1 文字を読み取り、それを配列に格納します。
  • インデックス 0 からこの配列の長さまで for ループを実行します。
  • このループは、配列の各文字を読み取り、一時変数に割り当てます。
  • 上記でネストされた別の for ループを実行します。これは、テスト対象の文字のインデックスから配列の長さまで実行されます。
  • この文字と現在の配列インデックス char との間の文字列比較を使用して、それらが等しい場合はカウンターがインクリメントされます。
  • 内側の For ループの完了後、デバッグ目的で char の頻度を出力しています。

質問: 文字の頻度が既に計算されている場合、プログラムで文字の頻度を再計算したくありません。たとえば、文字 "a" が 3 回出現する場合、最初の実行では正しい頻度が計算されます。ただし、次に "a" が出現すると、そのインデックスから最後までループが実行されるため、頻度は (実際の頻度 -1) になります。3 番目のオカレンスについても同様に、頻度は (実際の頻度 -2) です。

これを解決するには. 頻度がすでに評価されている文字をプッシュする別の一時配列を使用しました。

そして、次の for ループの実行時に、内側の for ループに入る前に、現在の char を評価済みの char の配列と比較し、フラグを設定します。そのフラグに基づいて、内側の for ループが実行されます。

これは私にとってはうまくいきません。それでも同じ結果です。

上記を達成するために私が書いたコードは次のとおりです。

#!/usr/bin/perl

use strict;
use warnings;

my $input=$ARGV[0];
my ($c,$ch,$flag,$s,@arr,@temp);

open(INPUT,"<$input");

while(defined($c = getc(INPUT)))
{
push(@arr,$c);
}

close(INPUT);

my $length=$#arr+1;

for(my $i=0;$i<$length;$i++)
{
$count=0;
$flag=0;
$ch=$arr[$i];
foreach $s (@temp)
{
    if($ch eq $s)
    {
        $flag = 1;
    }
}
if($flag == 0)
{
for(my $k=$i;$k<$length;$k++)
{
    if($ch eq $arr[$k])
    {
        $count = $count+1;
    }
}
push(@temp,$ch);
print "The character \"".$ch."\" appears ".$count." number of times in the         message"."\n";
}
}
4

5 に答える 5

4

あなたはあなたの人生を必要以上に難しくしています。ハッシュを使用します。

my %freq;

while(defined($c = getc(INPUT)))
{
  $freq{$c}++;
}

print $_, " ", $freq{$_}, "\n" for sort keys %freq;

$freq{$c}++に格納されている値をインクリメントします$freq{$c}。(未設定またはゼロの場合は1になります。)

印刷行は次と同等です。

foreach my $key (sort keys %freq) {
  print $key, " ", $freq{$key}, "\n";
}
于 2011-10-16T13:07:30.730 に答える
3

ファイル全体に対して単一の文字カウントを実行する場合は、他の人が投稿した推奨方法のいずれかを使用してください。ファイル内の各文字のすべての出現回数をカウントしたい場合は、次のことを提案します。

#!/usr/bin/perl

use strict;
use warnings;

# read in the contents of the file
my $contents;
open(TMP, "<$ARGV[0]") or die ("Failed to open $ARGV[0]: $!");
{
    local($/) = undef;
    $contents = <TMP>;
}
close(TMP);

# split the contents around each character
my @bits = split(//, $contents);

# build the hash of each character with it's respective count
my %counts = map { 
    # use lc($_) to make the search case-insensitive
    my $foo = $_; 

    # filter out newlines
    $_ ne "\n" ? 
        ($foo => scalar grep {$_ eq $foo} @bits) :
        () } @bits;

# reverse sort (highest first) the hash values and print
foreach(reverse sort {$counts{$a} <=> $counts{$b}} keys %counts) {
    print "$_: $counts{$_}\n";
}
于 2011-10-16T13:45:31.073 に答える
2

あなたが解決しようとしている問題を理解していないので、文字列内の文字を数えるより簡単な方法を提案します:

$string = "fooooooobar";
$char = 'o';
$count = grep {$_ eq $char} split //, $string;
print $count, "\n";

これは、$string (7) 内の $char の出現回数を出力します。これがよりコンパクトなコードを書くのに役立つことを願っています

于 2011-10-16T13:20:01.640 に答える
1

より高速なソリューション:

@result = $subject =~ m/a/g; #subject is your file

print "Found : ", scalar @result, " a characters in file!\n";

もちろん、「a」の代わりに変数を配置することも、出現回数をカウントしたい文字に対してこの行を実行することもできます。

于 2011-10-16T13:05:25.920 に答える
1

ワンライナーとして:

perl -F"" -anE '$h{$_}++ for @F; END { say "$_ : $h{$_}" for keys %h }' foo.txt
于 2011-10-16T15:26:29.957 に答える