UNIX 文字工具: 計算不同的字數

利用 tr 和 sort -u 我們可以得知一個檔案內一共有幾個不同的字。

我們先舉一個簡單的例子。首先用 tr 將所有空格都變成 LF 碼, 因此每個字都獨立成一列 (每一列的最後一個字之後本來就有一個 LF 碼)。 再用 sort -u 取出所有不同的字,如此即可。例如

tr ' ' '\012' < indian.txt | sort -u
所得是以下 14 個不同的字 (除了 one 到 ten 之外,只有 boys Indian Indians little):
boys
eight
five
four
Indian
Indians
little
nine
one
seven
six
ten
three
two
如果我們只想要知道檔案中用了幾個不同的字,可以說
tr A-Z a-z < indian.txt | tr ' ' '\012' | sort -u | wc -l
這個指令流程已經差強人意,底下我們要說些改善的方向。

以上的作法對 indian.txt 可以,因為它沒有句子。如果有句子, 那麼句子開頭的第一個字母會大寫,那麼 The 和 the 會被認為是兩個字。 這是我們不太樂意接受的結果。 所以我們應該首先用 tr 將所有大寫字母變成小寫。指令是

tr A-Z a-z < FILE | tr ' ' '\012' | sort -u

但是這還是不夠完美。以上所處理的,都是廣義字。 所以句子結尾處的標點符號,會和前面的字合成一個廣義字。 例如這個句子

This is a book, this is a book about trees.
則 book, 和 book 會被視為兩個不同的字。 這也是我們不太樂意接受的結果。 現在可以應用 tr 的 -d 和 -c (complement) 參數。 所謂 -dc 就是把不是指定的字元都刪除。例如
tr -dc 'a-z \012' < FILE
就是把 FILE 中不是小寫字母、不是空格、不是 LF 碼的字元都刪除掉。

最後,我們還要避免文件中有出現跳格。因此要用 expand 把它展開成空格。 但是連續兩個空格不可以置換成連續兩個 LF 碼,那就會出現一個空列。 而在 sort -u 之後,一個空列也會被誤認為是一個字,導至 wc -l 多計算了一個字。 此時可以用 tr 的 -s 參數,例如

tr -s a @ < FILE
把 FILE 中一個或多個連續出現的 a 都換成一個 @,例如
bark Baas aaaaoch
就變成了
b@rk B@s @och
tr -s a-z a-z < FILE
把 FILE 中連續出現的小寫字母,都換成一個,例如
This is a book, this is a book about trees.
就變成了
This is a bok, this is a bok about tres.

綜合前面的討論,得到一個一般性的指令如下:

tr A-Z a-z < FILE | expand | tr -dc 'a-z \012' | tr -s ' ' '\012' | sort -u
例如
This is   a book, this is   a book about trees.
就變成了
a
about
book
is
this
trees

習題

[ 前一節 ]‧[ 後一節 ]‧[ 回目錄 ]



注意:此處所有文件均為原著,個別的版權宣告日後會一一公布, 整體版面設計亦尚未完成。但仍請勿抄襲文字與圖片,以免觸犯著作權法。

Created: Nov 20, 2000
Last Revised: Nov 20, 2000
© Copyright 2000 Wei-Chang Shann 單維彰

shann@math.ncu.edu.tw