1-0

我如何用程式產生「國小常用字2000速查表」

兒子唸小學二年級時,我為了應付他寫功課(而且懶得查字典)的需求,幫他製做了一份「常用國字2000速查表」。身為程式人,這張表的內容當然不是一個字一個字打出來,而是用程式產生的。以下我就分享如何製做這張表,也是一次很有趣的problem solving過程。

在往下看之前,大家不妨先想想:如果是你,會怎麼產生這張表呢?

常用國字二千字
Picture by Arthur Liao (flickr)

一、取得2000常用字

不管是常用字1000也好,2000、3000也好,都要先取得帶有「字頻」的原始資料。我想到的方式,至少有二種:

  1. 找一堆文字檔(例如網路小說),用程式統計每個字出現的頻率,再篩選使用頻率最高的2000字。
  2. 下載現成的常用字列表,按照出現頻率排列。

第2種方法比較快,所以我先Google試試看。很幸運的,教育部網站有一個按照字頻排列的常用字彙表,共4155字,足夠我們使用了:

     ┌────┬───────────────────┬────┐
     │        │        字       彙      表           │常用國字│
     │ 序  號 ├───┬───┬─────┬─────┤標準字體│
     │        │頻序號│  字  │ 出現頻次 │ 百 分 比 │表序號  │
     ├────┼───┼───┼─────┼─────┼────┤
     │      1 │     1│  的  │   36053  │  3.42983 │   2724 │
     │      2 │     2│  一  │   12680  │  1.20628 │      1 │
     │      3 │     3│  是  │   10897  │  1.03666 │   1791 │
     │      4 │     4│  有  │    9424  │  0.89653 │   1842 │
     │      5 │     5│  在  │    9011  │  0.85724 │    743 │
     │      6 │     6│  人  │    8499  │  0.80853 │     68 │
     │      7 │     7│  不  │    8058  │  0.76658 │     10 │
     │      8 │     8│  大  │    6019  │  0.57260 │    848 │
     │      9 │     9│  中  │    6011  │  0.57184 │     20 │
     │     10 │    10│  為  │    5889  │  0.56023 │   2395 │
...

這是一個帶有全形表格符號的txt文字檔,用Vim的Ctrl-V可以快速選取/複製矩形區域,取得2000常用字。我們將這2000字存成2000.txt檔案:

2000.txt

的
一
是
有
在
...
屑
捲
棲
琴
塗

二、取得國字注音

我們需要先取得每個字的注音,才能將2000常用字按注音排序。有兩個常用的網站,可以下載中文字讀音資料:

  1. Unihan:http://www.unicode.org/charts/unihan.html
    Unihan是世界知名的中文字資料庫,由Unicode Consortium維護,其中的Unihan.zip是最重要的中文字資料來源之一。這裡面有個Unihan_Readings.txt檔案,可以找到每個中文字的國語和廣東話讀音:
    U+3400  kCantonese      jau1
    U+3400  kDefinition     (same as U+4E18 丘) hillock or mound
    U+3400  kMandarin       qiū
    U+3401  kCantonese      tim2
    U+3401  kDefinition     to lick; to taste, a mat, bamboo bark
    U+3401  kHanyuPinyin    10019.020:tiàn
    U+3401  kMandarin       tiàn
    U+3402  kDefinition     (J) non-standard form of U+559C 喜, to like, love, enjoy; a joyful thing
    U+3404  kMandarin       kuà
    U+3405  kCantonese      ng5
    U+3405  kDefinition     (an ancient form of U+4E94 五) five
    U+3405  kMandarin       wǔ
    ...
    
  2. 教育部國語辭典公眾授權網:http://epaper.edu.tw/entrance/
    這個網站有三本國語字典的原始資料,其中的《國語辭典簡編本》大小適中,適合我們這次使用。

因為教育部的檔案有注音符號,比Unihan資料庫方便,因此我們決定用教育部的檔案。首先下載《國語辭典簡編本》「文字資料庫」的dict_concised_2014_20150204.xls檔案,這裡面欄位很多,我們只需「字詞名」、「注音一式」這兩個欄位,其它欄位都刪掉:

字詞名 注音一式
八   ㄅㄚ
八拜之交    ㄅㄚ ㄅㄞˋ ㄓ ㄐㄧㄠ
八寶飯 ㄅㄚ ㄅㄠˇ ㄈㄢˋ
八寶粥 ㄅㄚ ㄅㄠˇ ㄓㄡ
八面玲瓏    ㄅㄚ ㄇㄧㄢˋ ㄌㄧㄥˊ ㄌㄨㄥˊ
八面威風    ㄅㄚ ㄇㄧㄢˋ ㄨㄟ ㄈㄥ
八方  ㄅㄚ ㄈㄤ
八德  ㄅㄚ ㄉㄜˊ
八年抗戰    ㄅㄚ ㄋㄧㄢˊ ㄎㄤˋ ㄓㄢˋ
八哥  ㄅㄚ ㄍㄜ

把這45000多條讀音從Excel複製/貼上到Vim的時後,出現一個小問題。我們發現有些儲存格裡帶有換行符號,導致資料變成2行,例如以下的「礡」這個字:

...
薄紗  ㄅㄛˊ ㄕㄚ
薄弱  ㄅㄛˊ ㄖㄨㄛˋ
"礡
"    ㄅㄛˊ
駁   ㄅㄛˊ
駁回  ㄅㄛˊ ㄏㄨㄟˊ
駁斥  ㄅㄛˊ ㄔˋ
...

為了讓後面的資料處理起來容易一些,我們需要先將這些異常的儲存格做normalization,將兩行變一行。我們可以利用Vim的:%s/^"\([^\t]*\)\n/\1替換指令,把"開頭、且不包含tab字元\t的每一行,與下一行接起來(也就是把行尾換行符號\n去掉);接著再用:%s/"//g替換換令,把所有的"符號去掉。

做完normalization,我們可以把一堆用不到的「詞條注音」先過濾掉。我們再次利用:%s/^\S\S.*\n/替換指令,把第一欄超過1個字的資料都刪掉(\S代表非空白字元),從45000多行刪到只剩下6000多行的「單字注音」:

八    ㄅㄚ
扒   (一)ㄅㄚ
叭   ㄅㄚ
巴   ㄅㄚ
吧   (一)ㄅㄚ
...
把   (一)ㄅㄚˇ
靶   ㄅㄚˇ
把   (二)ㄅㄚˋ
爸   ㄅㄚˋ
伯   (二)ㄅㄚˋ
罷   (一)ㄅㄚˋ
...

這裡我們發現另一個問題:有2個以上讀音的破音字,注音前面會出現(一)、(二)、(讀音)、(語音)等額外內容。我們可以用:%s/(.)//g以及:%s/(.音)//g這兩個換指令,把這些多餘的字串刪掉。最後的結果,存到bopomofo.txt檔案:

bopomofo.txt

八   ㄅㄚ
扒   ㄅㄚ
叭   ㄅㄚ
巴   ㄅㄚ
吧   ㄅㄚ
...
運   ㄩㄣˋ
慍   ㄩㄣˋ
醞   ㄩㄣˋ
韞   ㄩㄣˋ
蘊   ㄩㄣˋ

到這裡為止,我們有了2000常用字,也有了每個字的注音,接下來就可以為這2000字配上注音了。

三、常用字2000加注音

加注音的步驟,用程式處理起來比較快。我經常用Perl寫這類處理文字檔的小程式,當然用其它程式語言也是可以的。以下就是我寫的一行Perl:

$ perl -nle 'BEGIN {open F, "2000.txt"; while (<F>) {chomp; $w{$_}=1}}
my @a=split; print "$a[1]\t$a[0]" if $w{$a[0]}' bopomofo.txt > 2000a.txt

簡單解釋一下這段Perl程式:

  • -n:將bopomofo.txt逐行讀進來,執行程式中的所有指令(除了BEINGEND區塊以外)
  • -l:(1)讀bopomofo.txt的時候,自動去掉換行符號;(2)執行print指令的時候,自動加上換行符號
  • -e:命令列的Perl程式碼
  • BEGIN {...}:在-n開始將bopomofo.txt逐行讀進來之前,先執行一次的區塊
  • while (<F>) {chomp; $w{$_} = 1}}:將檔案F(也就是2000.txt)逐行讀進來;針對每一行,以chomp去掉行尾的換行符號,再以該行內容(也就是2000常用字的每個字)為key,將hash%w初始化
  • my @a = split:將$_(也就是讀進來的bopomofo.txt每一行)以空白字元為分隔符號、拆到array @a
  • print ... if $w{$a[0]}:如果hash %w裡找得到$a[0](也就是這一行的bopomofo.txt落在2000常用字範圍),就將這一行印出來;印出來時將兩欄順序對調(先印$a[1]再印$a[0]

執行完以上的Perl程式,檔案2000a.txt內容就是2000常用字加注音了:

2000a.txt

ㄅㄚ  八
ㄅㄚ  巴
ㄅㄚ  吧
ㄅㄚˊ 拔
ㄅㄚˇ 把
...
ㄩㄣˊ 雲
ㄩㄣˊ 員
ㄩㄣˇ 允
ㄩㄣˋ 孕
ㄩㄣˋ 運

四、將常用字2000按注音分組

為了進一步節省人工編輯時間,我們還可以用Vim將2000a.txt檔案再次加工,把同樣注音的字集中到同一行。以下是我在Vim中執行的替換指令:

:%s/^\(\S\+\)\(\t.*\)\n\1\t/\1\2

以上指令需要重覆執行5~6次左右,直到沒有新的替換產生為止。最後得到的常用字2000注音表,我們把它存到2000b.txt檔案:

2000b.txt

ㄅㄚ  八巴吧
ㄅㄚˊ 拔
ㄅㄚˇ 把
ㄅㄚˋ 把爸伯罷霸
˙ㄅㄚ 吧罷
ㄅㄛ  波般撥
ㄅㄛˊ 百伯柏勃博薄
ㄅㄛˋ 播薄
ㄅㄞˊ 白
ㄅㄞˇ 百擺
...

五、人工編輯

程式的部份到此為止。剩下是人工編輯的工作,包括:

  • 刪掉不常用的破音字(例如:唸作ㄅㄚˋ的「把」、「伯」)
  • 安裝注音字型
  • 用Word排版

最後完成的Word檔及PDF檔,可從這篇文章的連結下載:國小常用字2000速查表(4頁A4)

結語

為了完成這張表格,我總共用到Google、教育部網站、Vim、Perl等幾種不同工具,目標都是為了儘量節省人工作業時間。Vim的部份雖然可以寫一些小程式代替,但根據我個人經驗,用Vim省事很多,而且「所見即所得」,操作起來有安全感。(Vim還有很多強大的功能,例如錄製巨集指令等等,非常好用。)至於Perl,現在學的人應該越來越少了,但我認為Perl one-liner(一行Perl)是處理文字資料的「超級瑞士刀」,少有其它程式語言能比得上;當然也有人喜歡用awk,不過awk功能比較陽春就是了。

以上就是我製做「國小常用字2000速查表」的過程,提供給大家參考。如果你還有想到一些其它做法,歡迎提出來探討!

0筆討論 回應文章