计算文本文件中的单个单词

时间:2011-05-29 23:00:49

标签: regex perl

我正在尝试计算文本文件中特定单词出现的次数。文本文件作为perl程序的程序参数给出。

while($text = <>)
{
    @words = split (/\W*\s+\W*/, $text);
    @words = grep (/^[a-zA-Z\-]+$/, @words);
    foreach $word (@words)
    {
        $wordCount{$word}++;
    }
}

我对这些行没有清楚的认识 -

@words = split (/\W*\s+\W*/, $text);
@words = grep (/^[a-zA-Z\-]+$/, @words);

我知道split会将字符串拆分为数组变量,但是如何?它是非单词吗?我不明白split函数中使用的正则表达式。

grep做了什么以及它的正则表达式对我来说不清楚。

P.S。当我检查这个时,代码似乎有一个错误,因为如果我输入一个文本文件为 -

  快速的棕色狐狸跳过了   懒狗dog.rose是棕色,紫罗兰色   跳了狐狸。

仅对单词foxdog计算一次,这是不正确的。

这里有什么问题?

3 个答案:

答案 0 :(得分:2)

我不确定拆分数组是最节省内存的方法,特别是对于非常大的文本。如果你有一个几兆字节的文本文件,你将构建一个非常大的数组,它会占用大量内存。

相反,我会做这样的事情:

while ($text = <>) {
    while ($text =~ /([A-Za-z\-]+)/g)  {
        my $word = lc($1);    # dont diffrentiate between 'Dog' and 'dog'
        $count++;             # total word count
        $wordCount{$word}++;  # individual word count
    }
}

如果您碰巧找到任何希望包含在单词中的有效字符,那么添加新字符也很容易。即如果您认为this_file可以接受,请将字符更改为[A-Za-z\-_]

关于你的问题:

正则表达式\W*\s+W*表示:将非单词字符0与任意次数匹配,后跟一个任意数量的空格,后跟零到任意数量的非单词字符。一种奇怪的分割方式,但它基本上会在所有空格中分开,并删除过程中的所有非单词字符,以获得更正确的单个字数。 (例如,它不会将dog,dog视为两个不同的词语。)

grep本身将返回与正则表达式匹配的值列表。正则表达式将匹配@words中仅包含(从头到尾)字母,大写或小写以及连字符的任何数组值。如果值内有任何其他字符,grep将排除它。

错误是"dog.rose""fox."无法正确拆分,因为没有空格。因此,它们不会被隐含地清除非单词字符,因此将使用grep.

删除

答案 1 :(得分:1)

与这些问题一样,有一百万种不同的方式来定义“单词”是什么。将现有的一个在这里使用(允许使用内部破折号的字母序列),但使其适用于两个指出的失败案例:

my $text = 'the quick brown fox jumps over the lazy dog dog.rose is brown, violet jumps the fox.';
my %wordCount;
for my $word ( $text =~ /([a-zA-Z]+|-(?=[a-zA-Z\-])(?<=[a-zA-Z\-]-))+/g ) {
    ++$wordCount{$word};
}

for my $word ( sort { $wordCount{$a} <=> $wordCount{$b} || $a cmp $b } keys %wordCount ) {
     print "$word: $wordCount{$word}\n" 
}

答案 2 :(得分:0)

\W is matching word characters
\s is matching whitespace

正如您可能已经猜到的那样,它不起作用,因为dog.rose中的单词之间没有空格。

我会分开\ b(这意味着单词边界)。这应该比\ W * \ s + \ W *。

更简单,更正确
while($text = <>)
{
    @words = split (/\b/, $text);
    foreach $word (@words)
    {
        $wordCount{$word}++;
    }
}