awk脚本统计一组单词中字母出现最多最少频率

目录
  • 字母计数
  • 打印相对频率
  • 最后的完整程序

编写一个 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 <= len; i++) {
        c = substr($0, i, 1);
    }
}

如果使用一个全局字符串变量 LETTERS 来存储字母表,我就可以借助 index 函数来找到某个字符在字母表中的位置。我将扩展 gawk 代码示例,让它在输入数据中只取范围在 “a” 到 “z” 的字母:

BEGIN { LETTERS = "abcdefghijklmnopqrstuvwxyz" }
{
    len = length($0); for (i = 1; i <= len; i++) {
        c = substr($0, i, 1);
        ltr = index(LETTERS, c);
    }
}

需要注意的是,index 函数将返回字母在 LETTERS 字符串中首次出现的位置,第一个位置返回 1,如果没有找到则返回 0。如果我有一个大小为 26 的数组,我就可以利用这个数组来统计每个字母出现的次数。我将在下面的示例代码中添加这个功能,每当一个字母出现在输入中,我就让它对应的数组元素值增加 1(使用 ++):

BEGIN { LETTERS = "abcdefghijklmnopqrstuvwxyz" }
{
    len = length($0); for (i = 1; i <= len; i++) {
        c = substr($0, i, 1);
        ltr = index(LETTERS, c);
        if (ltr &gt; 0) {
            ++count[ltr];
        }
    }
}

打印相对频率

当 gawk 脚本统计完所有的字母后,我希望它能输出每个字母的频率。毕竟,我对输入中各个字母的个数没有兴趣,我更关心它们的 相对频率。

我将先统计字母 “a” 的个数,然后把它和剩余 “b” 到 “z” 字母的个数比较:

END {
    min = count[1]; for (ltr = 2; ltr <= 26; ltr++) {
        if (count[ltr] < min) {
            min = count[ltr];
        }
    }
}

在循环的最后,变量 min 会等于最少的出现次数,我可以把它为基准,为字母的个数设定一个参照值,然后计算打印出每个字母的相对频率。比如,如果出现次数最少的字母是 “q”,那么 min 就会等于 “q” 的出现次数。

接下来,我会遍历每个字母,打印出它和它的相对频率。我通过把每个字母的个数都除以 min 的方式来计算出它的相对频率,这意味着出现次数最少的字母的相对频率是 1。如果另一个字母出现的次数恰好是最少次数的两倍,那么这个字母的相对频率就是 2。我只关心整数,所以 2.1 和 2.9 对我来说是一样的(都是 2)。

END {
    min = count[1]; for (ltr = 2; ltr <= 26; ltr++) {
        if (count[ltr] < min) {
            min = count[ltr];
        }
    }
    for (ltr = 1; ltr <= 26; ltr++) {
        print substr(LETTERS, ltr, 1), int(count[ltr] / min);
    }
}

最后的完整程序

现在,我已经有了一个能够统计输入中各个字母的相对频率的 gawk 脚本:

#!/usr/bin/gawk -f
# 只统计 a-z 的字符,忽略 A-Z 和其他的字符
BEGIN { LETTERS = "abcdefghijklmnopqrstuvwxyz" }
{
    len = length($0); for (i = 1; i <= len; i++) {
        c = substr($0, i, 1);
        ltr = index(LETTERS, c);
        if (ltr < 0) {
            ++count[ltr];
        }
    }
}
# 打印每个字符的相对频率
END {
    min = count[1]; for (ltr = 2; ltr <= 26; ltr++) {
        if (count[ltr] < min) {
            min = count[ltr];
        }
    }
    for (ltr = 1; ltr <= 26; ltr++) {
        print substr(LETTERS, ltr, 1), int(count[ltr] / min);
    }
}

我将把这段程序保存到名为 letter-freq.awk 的文件中,这样一来,我就可以在命令行中更方便地使用它。

如果你愿意的话,你也可以使用 chmod +x 命令把这个文件设为可独立执行。第一行中的 #!/usr/bin/gawk -f 表示 Linux 会使用 /usr/bin/gawk 把这个文件当作一个脚本来运行。由于 gawk 命令行使用 -f 来指定它要运行的脚本文件名,你需要在末尾加上 -f。如此一来,当你在 shell 中执行 letter-freq.awk,它会被解释为 /usr/bin/gawk -f letter-freq.awk。

接下来我将用几个简单的输入来测试这个脚本。比如,如果我给我的 gawk 脚本输入整个字母表,每个字母的相对频率都应该是 1:

$ echo abcdefghijklmnopqrstuvwxyz | gawk -f letter-freq.awk
a 1
b 1
c 1
d 1
e 1
f 1
g 1
h 1
i 1
j 1
k 1
l 1
m 1
n 1
o 1
p 1
q 1
r 1
s 1
t 1
u 1
v 1
w 1
x 1
y 1
z 1

还是使用上述例子,只不过这次我在输入中添加了一个字母 “e”,此时的输出结果中,“e” 的相对频率会是 2,而其他字母的相对频率仍然会是 1:

$ echo abcdeefghijklmnopqrstuvwxyz | gawk -f letter-freq.awk
a 1
b 1
c 1
d 1
e 2
f 1
g 1
h 1
i 1
j 1
k 1
l 1
m 1
n 1
o 1
p 1
q 1
r 1
s 1
t 1
u 1
v 1
w 1
x 1
y 1
z 1

现在我可以跨出最大的一步了!我将使用 grep 命令和 /usr/share/dict/words 文件,统计所有仅由小写字母组成的单词中,各个字母的相对使用频率:

$ grep  '^[a-z]*$' /usr/share/dict/words | gawk -f letter-freq.awk
a 53
b 12
c 28
d 21
e 72
f 7
g 15
h 17
i 58
j 1
k 5
l 36
m 19
n 47
o 47
p 21
q 1
r 46
s 48
t 44
u 25
v 6
w 4
x 1
y 13
z 2

在 /usr/share/dict/words 文件的所有小写单词中,字母 “j”、“q” 和 “x” 出现的相对频率最低,字母 “z” 也使用得很少。不出意料,字母 “e” 是使用频率最高的。

via: https://opensource.com/article/21/4/gawk-letter-game

以上就是awk脚本统计一组单词中字母出现最多最少频率的详细内容,更多关于awk脚本统计字母频率的资料请关注我们其它相关文章!

(0)

相关推荐

  • awk统计文件中某关键词出现次数的命令

    awk -F "" '{for(i=1;i<=NF;++i) if($i=="a") ++sum}END{print sum}' test.c[root@xiaobb 5906]# awk '{for(i=1;i<=NF;++i) if($i=="test") ++sum}END{print sum}' test.c6[root@xiaobb 5906]# cat test.ctest testktesttesta testtest

  • Linux 中awk 提取包含某个关键字的段落

    前提 AWK是一种处理文本文件的语言,是一个强大的文本分析工具. 本文将使用命令awk将具有某个关键字的段落提取出来. 准备数据 "Finalizer" #3 daemon prio=8 os_prio=0 tid=0x00007fb2dc1aa800 nid=0x63f6 in Object.wait() [0x00007fb2be61f000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Obje

  • awk中查看包含某两列字符的用法

    [root@localhost /root]# netstat -tunlp |awk '/137/;/138/{print}' udp 0 0 192.168.1.200:137 0.0.0.0:* 539/nmbd udp 0 0 0.0.0.0:137 0.0.0.0:* 539/nmbd udp 0 0 192.168.1.200:138 0.0.0.0:* 539/nmbd udp 0 0 0.0.0.0:138 0.0.0.0:*

  • shell 里 awk print 的用法详解

    首先, 你需要先了解awk 的工作原理: 1.AWK读取输入文件一次一行. 2.对于每一行,它匹配在给定的顺序模式,如果匹配,执行相应的动作. 3.如果没有模式匹配,将执行任何行动. 4.在上面的语法,无论是搜索模式,或行动是可选的,但不能同时. 5.如果没有给出搜索模式,然后awk要执行每一行输入给定的行动. 6.如果没有给出动作,打印,这是默认的操作与模式相匹配的所有行. 7.空出的任何行动括号什么都不做.它不会执行默认的打印操作. 8.中的每个行动的声明应该用分号分隔.让我们创建emplo

  • awk脚本统计一组单词中字母出现最多最少频率

    目录 字母计数 打印相对频率 最后的完整程序 编写一个 awk 脚本来找到一组单词中出现次数最多(和最少)的单词. 近一段时间,我开始编写一个小游戏,在这个小游戏里,玩家使用一个个字母块来组成单词.编写这个游戏之前,我需要先知道常见英文单词中每个字母的使用频率,这样一来,我就可以找到一组更有用的字母块.字母频次统计在很多地方都有相关讨论,包括在 维基百科 上,但我还是想要自己来实现. Linux 系统在 /usr/share/dict/words 文件中提供了一个单词列表,所以我已经有了一个现成

  • 利用Python3实现统计大量单词中各字母出现的次数和频率的方法

    首先以只读方式打开单词文件,利用列表推导式创建两个列表 列表sta记录各单词出现的次数,列表freq记录各单词出现的频率 f = open('5500词.txt','r',encoding='utf-8') sta = [0 for i in range(26)] freq = [0 for i in range(26)] 单词格式如下所示: a [ei] art.一(个):每一(个):(同类事物中)任一个 abandon [ə'bændən] vt.离弃,丢弃:遗弃,抛弃:放弃 abdomen

  • Java统计英文句子中出现次数最多的单词并计算出现次数的方法

    本文实例讲述了Java统计英文句子中出现次数最多的单词并计算出现次数的方法.分享给大家供大家参考,具体如下: import java.util.*; /** * 统计出现次数最多的单词和它出现的次数 * * @author ZHR */ public class CountWord { public static String[] strTostrArray(String str) { /* * 将非字母字符全部替换为空格字符" " 得到一个全小写的纯字母字符串包含有空格字符 */ s

  • Python3实现统计单词表中每个字母出现频率的方法示例

    本文实例讲述了Python3实现统计单词表中每个字母出现频率的方法.分享给大家供大家参考,具体如下: 作为python字典与数组概念的运用,统计字母表中每个字母出现的频率,作为练习再合适不过. 解决问题过程中需要用到的知识点包括:字典的创建.增添元素,数组的创建.增添元素,数组的遍历等 这个问题解决的思路为:首先从文件中按行依次读入单词,去除换行符后添加到数组 new_list 中.依次遍历数组 new_list 的每一个字符串,将每个字符串连同上一次循环中的频率统计结果 old_d (old_

  • Python实现统计给定列表中指定数字出现次数的方法

    本文实例讲述了Python实现统计给定列表中指定数字出现次数的方法.分享给大家供大家参考,具体如下: 直接看实现: #!usr/bin/env python #encoding:utf-8 ''''' __Author__:沂水寒城 功能:给定一个列表计数指定数字出现的所有次数 ''' def count_num_func(num_list,num): ''''' 计数指定数字 ''' split_list=[] for one in num_list: split_list+=list(str

  • JS使用单链表统计英语单词出现次数

    本文实例为大家分享了JS 列出所有单词及其出现次数的实现代码,JS统计英语单词出现次数,可以调用LinkedList 类的方法orderInsert(), 以字母大小的顺序储存 英文字符串,同时记录英文单词出现的次数,供大家参考,具体内容如下 <html> <head> <title>Linked List</title> <meta charset="utf-8"> </head> <body> &l

  • php实现字符串首字母大写和单词首字母大写的方法

    本文实例讲述了php实现字符串首字母大写和单词首字母大写的方法.分享给大家供大家参考.具体分析如下: ucfirst可以对字符串首字母进行大小,ucwords可以对字符串中每个单词的首字母大写输出 <?php print ucfirst("hello world"); print ucwords("iam king of the jungle"); ?> 希望本文所述对大家的php程序设计有所帮助.

  • PHP统计数值数组中出现频率最多的10个数字的方法

    本文实例讲述了PHP统计数值数组中出现频率最多的10个数字的方法.分享给大家供大家参考.具体分析如下: 该问题属于TOPK范畴,统计单词出现频率,做报表,数据统计的时会常用! php代码如下: //随机生成数值数组 for($i=0;$i<1000;$i++){ $ary[]=rand(1,1000); } //统计数组中所有的值出现的次数 $ary=array_count_values($ary); arsort($ary);//倒序排序 $i=1; foreach($ary as $key=

  • java统计字符串单词个数的方法解析

    在一些项目中可能需要对一段字符串中的单词进行统计,我在这里写了一个简单的demo,有需要的同学可以拿去看一下. 不说废话了直接贴代码: 实现代码: /** * 统计各个单词出现的次数 * @param text */ public static void findEnglishNum(String text){ //找出所有的单词 String[] array = {".", " ", "?", "!"}; for (int

  • java计算给定字符串中出现次数最多的字母和该字母出现次数的方法

    本文实例讲述了java计算给定字符串中出现次数最多的字母和该字母出现次数的方法.分享给大家供大家参考,具体如下: import Java.util.Collections; import java.util.Map; import java.util.TreeMap; public class TestStringSplict { public static void main(String[] args){ String str = "aaaaaaacccccccccccccccccccccc

随机推荐