如何在perl中打印单词的频率?

时间:2014-03-02 11:24:36

标签: perl

open INP,"<C:\\Users\\hanadi\\Documents\\cs.txt";
while ($line=<INP>)
{
    chomp($line);
    @list=split/\s+/,$line;
    foreach $w (@list)
    {
        $wordfreq{$w}++;
    }
}
foreach $w2(keys>wordfreq)
{
    print "$w2==>$wordfreq{$w}";
}

我想打印每个单词及其频率。现在我希望Perl中的代码能够跳转并打印上面的信息

排名(> 100),但不打印

每一行,每1000字只打印一行(否则会

要打印的行数太多)按频率降序排列

减少具有相同频率的单词之间的字母顺序。

2 个答案:

答案 0 :(得分:2)

这个问题的第一个问题是定义单词“word”。我们假设您的一条评论中标点符号不是“单词”的一部分,因为您在询问如何“...从文本中删除标点符号...”

对此的一个解决方案是使用正则表达式来捕获“单词”字符,即字母数字和下划线,方法是将文本与正则表达式中的\w进行匹配。

构建哈希,其中键是单词,关联值是计数,是要走的路。但是,在执行此操作时,您需要确保密钥完全相同,即全部为UPPER或全部为低。

在构建此哈希之后,您可以按有序值(频率)按降序对输出进行排序,并使用计数器仅打印前100个单词。将存在具有相同频率计数的单词 - 尤其是仅出现一次。你是如何想要这些打印的,因为它们是否会出现在前100名列表中会有所不同。我建议按字母顺序排列这些案例。

给出上述内容,请考虑以下解决方案,该解决方案使用以下代码上方的文本作为语料库:

use strict;
use warnings;

my %hash;

open my $fh, '<', 'words.txt' or die $!;
while (<$fh>) {
    $hash{ lc $1 }++ while /(\w+)/g;
}
close $fh;

my $i = 1;

for my $word ( sort { $hash{$b} <=> $hash{$a} || $a cmp $b } keys %hash ) {
    print "$i. $word: ($hash{$word})\n" if $i++ < 100 or !( $i % 1000 );
}

部分输出:

1. the: (22)
2. to: (8)
3. a: (5)
4. you: (5)
5. is: (4)
6. of: (4)
7. this: (4)
8. word: (4)
9. all: (3)
10. and: (3)
...
96. punctuation: (1)
97. punctuations: (1)
98. since: (1)
99. sort: (1)
100. suggest: (1)

限制:

在某些占有形式的单词(例如word's)的情况下,可以看到捕获单词字符所导致的一个问题。在这种情况下,words都会被捕获为单词。如果你想保留这样的标点符号,并在空白处split,你可以使用以下代替正则表达式行:

$hash{ lc $_ }++ for split ' ';

希望这有帮助!

答案 1 :(得分:0)

请注意所有的amons回复,并且始终rtq。 (好现场amon)。

(我已经确定)你的问题是,一旦你构造了你的wordcount哈希,你现在需要反转哈希,这样你就可以将值排序成某种顺序。这样做的问题是,多个单词可能具有相同的计数,并会覆盖先前存储的单词。

要执行此操作,您需要将数组存储在哈希值中,这是通过使用对数组的引用来完成的。散列值可能只是标量,数组不是标量,而是对数组的引用。

在重新编写您的问题时,我更新了开启和关闭调用以使用标量文件句柄,并进行适当的错误处理(或死亡),并将您的foreach语句转换为“地图”。这些可能需要一些时间来掌握,所以不要复制和粘贴它们。而是专注于反转哈希以及如何访问数组。这对你来说可能相当复杂,所以我把这些部分留在了foreach风格中。

'each'关键字从哈希中获取键/值对,并且通常以这种方式用于处理while语句中的哈希值。

你仍然需要按照amons建议和检索前100名的方法将计数转换为频率。“$ c”变量中的计数有一个线索。

#!/usr/bin/perl
# word count #wct.pl
use warnings;
use strict;

my (%wordfreq);

open my $input, '<', 'wc.txt'
 or die "cannot open wc txt file $!";

map { $wordfreq{ $_ }++; } (split /\s+/, $_) while <$input> ;

close $input
  or die "cannot close wc txt file $!";

# print (
# map {"$_ has ". $wordfreq{$_} . "\n" } (keys %wordfreq)
# );

foreach (keys %wordfreq){
#  print "$_ has ". $wordfreq{$_} . "\n"
}


my %invertedhash;

while (my ($key,$value) = each %wordfreq){

   push @{$invertedhash{$value}}, $key;

}

my $c;

foreach (reverse sort keys %invertedhash){

last if $c++ == 2;
print "words with a count of $_ are @{$invertedhash{$_}} \n";

}

exit 0;

样品

one two two
three three three four
four four four five
five five five

产生

words with a count of 4 are four five
words with a count of 3 are three

希望这有帮助。