網(wǎng)站首頁(yè) 編程語(yǔ)言 正文
編寫(xiě)一個(gè) awk 腳本來(lái)找到一組單詞中出現(xiàn)次數(shù)最多(和最少)的單詞。
近一段時(shí)間,我開(kāi)始編寫(xiě)一個(gè)小游戲,在這個(gè)小游戲里,玩家使用一個(gè)個(gè)字母塊來(lái)組成單詞。編寫(xiě)這個(gè)游戲之前,我需要先知道常見(jiàn)英文單詞中每個(gè)字母的使用頻率,這樣一來(lái),我就可以找到一組更有用的字母塊。字母頻次統(tǒng)計(jì)在很多地方都有相關(guān)討論,包括在 維基百科 上,但我還是想要自己來(lái)實(shí)現(xiàn)。
Linux 系統(tǒng)在 /usr/share/dict/words 文件中提供了一個(gè)單詞列表,所以我已經(jīng)有了一個(gè)現(xiàn)成的單詞列表。然而,盡管這個(gè) words 文件包含了很多我想要的單詞,卻也包含了一些我不想要的。我想要的單詞首先不能是復(fù)合詞(即不包含連接符和空格的單詞),也不能是專有名詞(即不包含大寫(xiě)字母單詞)。為了得到這個(gè)結(jié)果,我可以運(yùn)行 grep 命令來(lái)取出只由小寫(xiě)字母組成的行:
$ grep ?'^[a-z]*$' /usr/share/dict/words
這個(gè)正則表達(dá)式的作用是讓 grep 去匹配僅包含小寫(xiě)字母的行。表達(dá)式中的字符 ^ 和 $ 分別代表了這一行的開(kāi)始和結(jié)束。[a-z] 分組僅匹配從 “a” 到 “z” 的小寫(xiě)字母。
下面是一個(gè)輸出示例:
$ grep ?'^[a-z]*$' /usr/share/dict/words | head
a
aa
aaa
aah
aahed
aahing
aahs
aal
aalii
aaliis
沒(méi)錯(cuò),這些都是合法的單詞。比如,“aahed” 是 “aah” 的過(guò)去式,表示在放松時(shí)的感嘆,而 “aalii” 是一種濃密的熱帶灌木。
現(xiàn)在我只需要編寫(xiě)一個(gè) gawk 腳本來(lái)統(tǒng)計(jì)出單詞中各個(gè)字母出現(xiàn)的次數(shù),然后打印出每個(gè)字母的相對(duì)頻率。
字母計(jì)數(shù)
一種使用 gawk 來(lái)統(tǒng)計(jì)字母?jìng)€(gè)數(shù)的方式是,遍歷每行輸入中的每一個(gè)字符,然后對(duì) “a” 到 “z” 之間的每個(gè)字母進(jìn)行計(jì)數(shù)。substr 函數(shù)會(huì)返回一個(gè)給定長(zhǎng)度的子串,它可以只包含一個(gè)字符,也可以是更長(zhǎng)的字符串。比如,下面的示例代碼能夠取到輸入中的每一個(gè)字符 c:
{ len = length($0); for (i = 1; i <= len; i++) { c = substr($0, i, 1); } }
如果使用一個(gè)全局字符串變量 LETTERS 來(lái)存儲(chǔ)字母表,我就可以借助 index 函數(shù)來(lái)找到某個(gè)字符在字母表中的位置。我將擴(kuò)展 gawk 代碼示例,讓它在輸入數(shù)據(jù)中只取范圍在 “a” 到 “z” 的字母:
BEGIN { LETTERS = "abcdefghijklmnopqrstuvwxyz" } { len = length($0); for (i = 1; i <= len; i++) { c = substr($0, i, 1); ltr = index(LETTERS, c); } }
需要注意的是,index 函數(shù)將返回字母在 LETTERS 字符串中首次出現(xiàn)的位置,第一個(gè)位置返回 1,如果沒(méi)有找到則返回 0。如果我有一個(gè)大小為 26 的數(shù)組,我就可以利用這個(gè)數(shù)組來(lái)統(tǒng)計(jì)每個(gè)字母出現(xiàn)的次數(shù)。我將在下面的示例代碼中添加這個(gè)功能,每當(dāng)一個(gè)字母出現(xiàn)在輸入中,我就讓它對(duì)應(yīng)的數(shù)組元素值增加 1(使用 ++):
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]; } } }
打印相對(duì)頻率
當(dāng) gawk 腳本統(tǒng)計(jì)完所有的字母后,我希望它能輸出每個(gè)字母的頻率。畢竟,我對(duì)輸入中各個(gè)字母的個(gè)數(shù)沒(méi)有興趣,我更關(guān)心它們的 相對(duì)頻率。
我將先統(tǒng)計(jì)字母 “a” 的個(gè)數(shù),然后把它和剩余 “b” 到 “z” 字母的個(gè)數(shù)比較:
END { min = count[1]; for (ltr = 2; ltr <= 26; ltr++) { if (count[ltr] < min) { min = count[ltr]; } } }
在循環(huán)的最后,變量 min 會(huì)等于最少的出現(xiàn)次數(shù),我可以把它為基準(zhǔn),為字母的個(gè)數(shù)設(shè)定一個(gè)參照值,然后計(jì)算打印出每個(gè)字母的相對(duì)頻率。比如,如果出現(xiàn)次數(shù)最少的字母是 “q”,那么 min 就會(huì)等于 “q” 的出現(xiàn)次數(shù)。
接下來(lái),我會(huì)遍歷每個(gè)字母,打印出它和它的相對(duì)頻率。我通過(guò)把每個(gè)字母的個(gè)數(shù)都除以 min 的方式來(lái)計(jì)算出它的相對(duì)頻率,這意味著出現(xiàn)次數(shù)最少的字母的相對(duì)頻率是 1。如果另一個(gè)字母出現(xiàn)的次數(shù)恰好是最少次數(shù)的兩倍,那么這個(gè)字母的相對(duì)頻率就是 2。我只關(guān)心整數(shù),所以 2.1 和 2.9 對(duì)我來(lái)說(shuō)是一樣的(都是 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); } }
最后的完整程序
現(xiàn)在,我已經(jīng)有了一個(gè)能夠統(tǒng)計(jì)輸入中各個(gè)字母的相對(duì)頻率的 gawk 腳本:
#!/usr/bin/gawk -f # 只統(tǒng)計(jì) 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]; } } } # 打印每個(gè)字符的相對(duì)頻率 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 的文件中,這樣一來(lái),我就可以在命令行中更方便地使用它。
如果你愿意的話,你也可以使用 chmod +x 命令把這個(gè)文件設(shè)為可獨(dú)立執(zhí)行。第一行中的 #!/usr/bin/gawk -f 表示 Linux 會(huì)使用 /usr/bin/gawk 把這個(gè)文件當(dāng)作一個(gè)腳本來(lái)運(yùn)行。由于 gawk 命令行使用 -f 來(lái)指定它要運(yùn)行的腳本文件名,你需要在末尾加上 -f。如此一來(lái),當(dāng)你在 shell 中執(zhí)行 letter-freq.awk,它會(huì)被解釋為 /usr/bin/gawk -f letter-freq.awk。
接下來(lái)我將用幾個(gè)簡(jiǎn)單的輸入來(lái)測(cè)試這個(gè)腳本。比如,如果我給我的 gawk 腳本輸入整個(gè)字母表,每個(gè)字母的相對(duì)頻率都應(yīng)該是 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
還是使用上述例子,只不過(guò)這次我在輸入中添加了一個(gè)字母 “e”,此時(shí)的輸出結(jié)果中,“e” 的相對(duì)頻率會(huì)是 2,而其他字母的相對(duì)頻率仍然會(huì)是 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
現(xiàn)在我可以跨出最大的一步了!我將使用 grep 命令和 /usr/share/dict/words 文件,統(tǒng)計(jì)所有僅由小寫(xiě)字母組成的單詞中,各個(gè)字母的相對(duì)使用頻率:
$ 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 文件的所有小寫(xiě)單詞中,字母 “j”、“q” 和 “x” 出現(xiàn)的相對(duì)頻率最低,字母 “z” 也使用得很少。不出意料,字母 “e” 是使用頻率最高的。
via:?https://opensource.com/article/21/4/gawk-letter-game
原文鏈接:https://linux.cn/article-14375-1.html
相關(guān)推薦
- 2022-08-02 C#如何自定義multipart/form-data的解析器_C#教程
- 2023-09-18 element-plus 字體變色之cell-style
- 2022-10-25 在PyCharm中使用FMEObjects的操作步驟_python
- 2022-03-25 Redis分布式鎖如何實(shí)現(xiàn)續(xù)期_Redis
- 2022-07-26 golang中slice切片使用的誤區(qū)
- 2022-09-17 Redis請(qǐng)求處理的流程分析_Redis
- 2022-11-17 使用python如何實(shí)現(xiàn)泛型函數(shù)_python
- 2023-03-29 goland遠(yuǎn)程調(diào)試k8s上容器的實(shí)現(xiàn)_Golang
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲(chǔ)小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過(guò)濾器
- Spring Security概述快速入門(mén)
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡(jiǎn)單動(dòng)態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對(duì)象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支