如何使用perl去除频率计算中的原始字符串

Yuk*_*iku 3 perl

我在使用Perl从文本文件读取的字符串列表的频率计算方面遇到了麻烦.我想要做的是,分别计算每一行中的字符数.我的代码可以正常工作,但它也将原始字符串计算为单个字符.

这是我的代码,

sub cal_frequency{
    while (my @row = <$fd>){
    chomp;
    for (my $i=0; $i<=147; $i++){
    my %count;
            print "$row[$i]\n";
            foreach my $str (split //, $row[$i]) {
                $count{$str}++;
            }
            foreach my $str (sort keys %count) {
                printf "%-31s %s\n", $str, $count{$str} ;
            }
        }
    }   
}
Run Code Online (Sandbox Code Playgroud)

这是我得到的输出.

HMHHMSHHHNHHMEHFFHHHHHHHDHDE
                               1
D                               2
E                               2
F                               2
H                               17
M                               3
N                               1
S                               1
LLLWLFLLWLWLLWWLLLLFLLLLWLFW
                               1
F                               3
L                               18
W                               7
TTTTTDTTTTTTTTTTSTTTTSSTTATT
                               1
A                               1
D                               1
...
...
...
Run Code Online (Sandbox Code Playgroud)

有没有人可以帮我弄清楚代码有什么问题.

sim*_*que 8

你正在扼杀错误的变量.您正在阅读您的输入@row,但是您只需在chomp;没有参数的情况下进行调用.扼杀$_,而不是@row.

while (my @row = <$fd>){
    chomp @row;
    # ...
Run Code Online (Sandbox Code Playgroud)

你可能已经找到了自己.如果输出%count每个输入行的实际内容,您将看到有一个新行\n被计算一次.所以你看到的第一行

HMHHMSHHHNHHMEHFFHHHHHHHDHDE
                               1
Run Code Online (Sandbox Code Playgroud)

实际上不是完整的字符串.它是字符串末尾的换行符.试试这个.我建议你将你的迭代变量改为只做一行,这样你就不会被输出所淹没.

for ( my $i = 0; $i <= 1; $i++ ) {

    # ...
    foreach my $str ( sort keys %count ) {
        printf "%-31s %s\n", $str, $count{$str};
    }
    use Data::Dumper;
    print Dumper \%count;
}
Run Code Online (Sandbox Code Playgroud)

你现在会看到这个:

$VAR1 = {
          'A' => 1,
          'S' => 3,
          'T' => 23,
          '
' => 1,
Run Code Online (Sandbox Code Playgroud)

有线路.


你的代码有点奇怪.你做了很多不必要的事情.我将尝试为您解释它们以简化您的代码.

你的while循环只运行一次,因为你正在将整个文件@row一次性啜饮.

sub cal_frequency {
    while ( my @row = <DATA> ) {
        print "while iteration\n";
Run Code Online (Sandbox Code Playgroud)

我在printf这里省略了输出.

while iteration
HMHHMSHHHNHHMEHFFHHHHHHHDHDE
LLLWLFLLWLWLLWWLLLLFLLLLWLFW
TTTTTDTTTTTTTTTTSTTTTSSTTATT
Run Code Online (Sandbox Code Playgroud)

如您所见,迭代只有一次.如果你有一个很长的文件,那么逐行读取它会更聪明.

while ( my $row = <DATA> ) {
    chomp $row;
    # ...
}
Run Code Online (Sandbox Code Playgroud)

一旦你这样做,你的C风格for循环就会过时.实际上,该循环将程序耦合到输入,因为您在那里有硬编码的输入行数.没有这个循环,程序可以处理任意长的文件(比如你向我们展示的三条线和我正在使用的文件).

尽可能晚地声明变量并尽可能接近您需要的变量也是一种很好的风格.我已经移动my %count并改变了缩进.

sub cal_frequency {
    while ( my $row = <DATA> ) {
        chomp $row;
        print "$row\n";

        my %count;
        foreach my $str ( split //, $row ) {
            $count{$str}++;
        }
        foreach my $str ( sort keys %count ) {
            printf "%-31s %s\n", $str, $count{$str};
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

现在更清楚的是发生了什么.

在您的代码中,您使用的是词法文件句柄.那很棒.但它似乎是在子程序之外创建的.将它作为一个参数传递会更好.

最后,$str在两个foreach循环中选择变量名称令人困惑.当我看到字符串时,我会想到很长的单词或其他东西.但是在这里你特别希望将你的字符串(行)分成字符.这是长度为1的字符串.将它们命名为字符.

这是最后的节目.

use strict;
use warnings;

sub cal_frequency {
    my ($fh) = @_;

    while ( my $row = <$fh> ) {
        chomp $row;
        print "$row\n";

        my %count;
        foreach my $chr ( split //, $row ) {
            $count{$chr}++;
        }
        foreach my $chr ( sort keys %count ) {
            printf "%-31s %s\n", $chr, $count{$chr};
        }
    }
}

cal_frequency(\*DATA);

__DATA__
HMHHMSHHHNHHMEHFFHHHHHHHDHDE
LLLWLFLLWLWLLWWLLLLFLLLLWLFW
TTTTTDTTTTTTTTTTSTTTTSSTTATT
Run Code Online (Sandbox Code Playgroud)

和输出.

HMHHMSHHHNHHMEHFFHHHHHHHDHDE
D                               2
E                               2
F                               2
H                               17
M                               3
N                               1
S                               1
LLLWLFLLWLWLLWWLLLLFLLLLWLFW
F                               3
L                               18
W                               7
TTTTTDTTTTTTTTTTSTTTTSSTTATT
A                               1
D                               1
S                               3
T                               23
Run Code Online (Sandbox Code Playgroud)