编写一个 awk 脚本来找到一组单词中出现次数最多(和最少)的单词。
近一段时间,我开始编写一个小游戏,在这个小游戏里,玩家使用一个个字母块来组成单词。编写这个游戏之前,我需要先知道常见英文单词中每个字母的使用频率,这样一来,我就可以找到一组更有用的字母块。字母频次统计在很多地方都有相关讨论,包括在 维基百科 上,但我还是想要自己来实现。
Linux 系统在 /usr/share/dict/words
文件中提供了一个单词列表,所以我已经有了一个现成的单词列表。然而,尽管这个 words
文件包含了很多我想要的单词,却也包含了一些我不想要的。我想要的单词首先不能是复合词(即不包含连接符和空格的单词),也不能是专有名词(即不包含大写字母单词)。为了得到这个结果,我可以运行 grep
命令来取出只由小写字母组成的行:
$ grep '^[a-z]*$' /usr/share/dict/words
这个正则表达式的作用是让 grep
去匹配仅包含小写字母的行。表达式中的字符 ^
和 $
分别代表了这一行的开始和结束。[a-z]
分组仅匹配从 “a” 到 “z” 的小写字母。
下面是一个输出示例:
$ grep '^[a-z]*$' /usr/share/dict/words | head
a
aa
aaa
aah
aahed
aahing
aahs
aal
aalii
aaliis
没错,这些都是合法的单词。比如,“aahed” 是 “aah” 的过去式,表示在放松时的感叹,而 “aalii” 是一种浓密的热带灌木。
现在我只需要编写一个 gawk
脚本来统计出单词中各个字母出现的次数,然后打印出每个字母的相对频率。
字母计数
一种使用 gawk
来统计字母个数的方式是,遍历每行输入中的每一个字符,然后对 “a” 到 “z” 之间的每个字母进行计数。substr
函数会返回一个给定长度的子串,它可以只包含一个字符,也可以是更长的字符串。比如,下面的示例代码能够取到输入中的每一个字符 c
:
{
len = length($0); for (i = 1; i