4.5 统计特定文件中的词频

查找文件中使用单词的频率是一个很有意思的练习,在这个练习中会应用到你已学到的文本处理技巧。统计词频的方法有很多种。让我们看看具体的做法。

4.5.1 预备知识

我们可以使用关联数组、awksedgrep等不同的方式来解决这个问题。

4.5.2 实战演练

单词是由空格和点号分隔的字母组合。首先我们应该解析出给定文件中出现的所有单词,这样才能开始统计每个单词的个数。单词解析可以用正则表达式配合sedawkgrep等工具来完成。

要找出每个单词出现的次数,我们要采用一种与众不同的方法。有一种统计词频的方法是用一个循环来遍历每一个单词,然后用另一个循环来检查单词是否相同。如果相同,则增加计数并在文件尾部进行打印。这不是一种高效的方法。在关联数组中,我们将单词作为数组索引,单词计数作为数组值。通过遍历每一个单词,我们只需要使用一个循环就能完成统计任务。将数组值初始化为0,并使用array[word]=array[word] + 1就可以得到一个包含各单词出现次数的数组。

现在就来动手试试吧。创建脚本如下:

  1. #!/bin/bash
  2. #文件名: word_freq.sh
  3. #用途: 计算文件中单词的词频
  4. if [ $# -ne 1 ];
  5. then
  6. echo "Usage: $0 filename";
  7. exit -1
  8. fi
  9. filename=$1
  10. egrep -o "\b[[:alpha:]]+\b" $filename | \
  11. awk '{ count[$0]++ }
  12. END{ printf("%-14s%s\n","Word","Count") ;
  13. for(ind in count)
  14. { printf("%-14s%d\n",ind,count[ind]); }
  15. }'

输出如下:

  1. $ ./word_freq.sh words.txt
  2. Word Count
  3. used 1
  4. this 2
  5. counting 1

4.5.3 工作原理

egrep -o "\b[[:alpha:]]+\b" $filename用来只输出单词。用 -o选项打印由换行符分隔的匹配字符序列。这样我们就可以在每行中列出一个单词。

\b 是单词边界标记符。[:alpha:] 是表示字母的字符类。

awk命令用来避免对每一个单词进行迭代。因为awk默认对每一行都执行{}块中的语句,所以我们就不需要再为同样的事手动指定循环了。借助关联数组,当执行count[$0]++时,单词计数就增加。最后,在END{}语句块中通过迭代所有的单词,就可以打印出单词及它们各自出现的次数。

4.5.4 参考

  • 1.6节讲解了Bash中的数组。

  • 4.7节介绍了awk命令。