2007年12月8日星期六

IT中文環境的血淚史

作者:蔡學鏞

身為一個中文電腦使用者,我有過太多的無奈,這些無奈是西方人無法體會的。大多數知名的編程語言、作業系統、應用軟體,都是西方人開發的,他們往往一開始的時候不會把中日韓(CJK)的語言需求當一回事,這讓我們吃足了苦頭。

作業系統

二十多年前,為了要讓電腦具有快速的(繁體)中文環境,每次開機後都必須插入中文磁片,花一段時間安裝倚天中文(或大千、零壹、天龍中文),而且都是16或24的點陣字型(bitmap font),只要把字放大,就其醜無比。為了要加速中文的載入與顯示,必須安裝超貴的倚天中文卡,而早期的倚天中文卡只能使用在單色模式。當時,歐美的電腦使用者,根本不需要這麼麻煩,人家開機後就可以直接用電腦了,令我們感到羨慕。

後來Windows 3.x時代,可以方便地使用中文,但是檔案名稱不能使用中文,進入Windows 95之後才解除此限制,微軟平臺上的中文問題也漸漸變得比較少了。但其他平臺還是存在這個問題,Linux一開始不支援雙位元語言,BeOS也不支援中文,我們必須用一些奇門遁甲的方式,辛苦地讓這些OS上面顯示中文。當中文顯示出來的剎那,感動得都快掉淚了。

繁體中文的編碼最常用的是Big-5,這是一種雙位元組字元集(Double-Byte Character Set,DBCS),但是不同平臺的Big-5字集還不太一樣。當我把在Windows平臺上寫好的文章交給MacOS的排版人員,最後一定要仔細校對排版後的輸出。因為兩者的Big-5字集有些小差異,所以有些中文字可能會不一樣。

編程語言

經過這段時間大家的努力,現在,至少主流的OS都不會有中文的問題了。但是程式環境可不見得如此,繁體Windows上使用CP950編碼,這是混合Big-5和ASCII的變動長度編碼方式。對於這種變動長度的編碼方式,如果程式環境沒有特別處理,常常會發生問題。著名的「許、功、蓋」問題就是如此,這幾個中文字的第二個位元組都是ASCII的反斜線(\),剛好是某些程式語言的特殊字元,或者脫字序列(Escape Sequence)字元,所以會出問題,根據這樣來推估,不只「許、功、蓋」這三個字,還有相當多字都會出問題,包括「廄、琵、崤、淚、豹」。

不同的程式環境可能會有不同的特殊字元。甲語言出問題的中文字可能是「許、功、蓋」,乙語言出問題的中文字可能是「扁、夏、抬」,所以每個語言必須用不同的方式處理特殊字元的問題。

幸好我們開始有Unicode,早期的Unicode是16位元的,後來又擴充到32位元。許多號稱支援Unicode的平臺,其實並沒有100%支援Unicode。至少在Windows上,當我測試Unicode的中文組字功能時,發現是行不通的。例如:「2FF1 4E95 86D9」無法呈現正確組合出來的1個中文字,而是3個中文字。這是因為Windows API的TextOut() 函式與DrawText() 函式(以及相關函式)沒有處理中文組字。後面討論到「中文造字」時,會有更詳細的說明。

Java雖然一開始就支援Unicode,但是前幾年在AWT/Swing上顯示的中文很不美觀,程式設計上也會遇到一些問題。我就常常收到讀者的E-mail,詢問如何在Java上解決特定的中文問題。這幾年下來,這些問題似乎在Java上都已經漸漸消失了。.NET平臺上的語言對於DBCS與Unicode的支援也不錯。但是Java和.NET畢竟都是跨國大公司的產品,所以有考慮到DBCS與Unicode,是很自然的。Ruby就比較特別了,由於Ruby是日本人(摩門教徒)設計的編程語言,所以Ruby一開始就有考慮到東亞的語言。

應用軟體與中文亂碼

平臺有支援中文,編程語言相容於中文,但開發出來的應用程式卻不見得如此,所以有的應用程式只要遇到中文,一律變成亂碼,但是這樣的例子已經越來越少了。

之所以會看到亂碼,就是「編碼的方式」和「解碼的方式」不同所造成的。比方說,用DBCS的中文編碼,卻用ASCII解碼,把每個中文字當作兩個「擴充ASCII」字元顯示;或者,把簡體中文GB2312編碼的內容,當作繁體中文Big-5解碼顯示,當然會看到不知所云的內容。

就算程式支援多種編碼,也會因為收到的內容沒有標示編碼,而造成解碼錯誤。我的Office 2003收件匣,只要收到簡體中文標題的郵件,標題就會呈現亂碼。別人的Office 2003沒這個問題,但我重新安裝好幾次,結果還是一樣,我只好將就著用。沒想到幾個月後,我養成一種功力,我可以閱讀郵件標題的中文亂碼解讀出簡體中文一些常用詞彙。比方說,當我看到郵件標題為「絆珂汜斕疑」,我就知道其實這幾個繁體中文字編碼對應到簡體中文是「蔡先生你好」。我考慮把這項了不起的「閱讀亂碼」才華加入我的履歷表中。

字型檔體積

解決了中文編碼,至於中文字型又是一個問題。在Windows上,一個不算美觀的中文TrueType字型需要約4 MB,像「隸書」這種每個筆畫「要斷不斷」的字型,檔案更大一些,接近10 MB,而專業印刷(而非螢幕顯示)所使用的字型,由於相當細緻,字型檔案也就更大得多。
中文字型檔案內有大量重複的資訊,相當浪費。例如以「木」為左邊部首的中文字,恐怕不下一百個,每個字的glyph資料都重複描述「木」的外框,這是相當大的浪費。我粗估,如果壓縮得當,搭配自動調整筆畫寬鬆的演算法,原本13,000字的5~10MB字型檔,可以壓縮到100 K。甚至可以讓演算法搭配各種參數組合,只需要少數參數資料,就可以產生不同的字體。我估計,多一個字型可能只需要多10KB,而不是多100KB(因為字的組成資料可以重複運用)。

目前,只有嵌入式系統會關注到中文字型檔案的大小,而在一般PC上我們不會把這當一回事。事實上,為了保持文件顯示效果的一致,有時候我們會嵌入字型。如果字型太大,或者使用太多字型,可能也會造成文件檔案變大。大多數允許嵌入字型的檔案格式(例如:PDF),都允許只嵌入文件中有真正使用到的文字。但儘管如此,只要有嵌入字型的檔案,多個幾MB是免不了的。
把形音義同時納入考量,可以解決中文字型太大,以及輸入法的一些問題。有一些單位在做這樣的研究,我也有看到不錯的產品,但似乎還有相當大的改進空間。發明倉頡輸入法,人稱中文電腦之父的朱邦復,似乎也有做過相關的研究。可惜他最近沈迷於「中文詩詞動畫」的研究,請恕我無知,我不知道以目前來說,中文詩詞動畫有什麼重要的?

我之所以對中文字型的壓縮這麼執著,其實是有原因的。研究所時就讀清華大學Computer Science,我們實驗室是「視訊通訊實驗室」。對於視訊通訊來說,壓縮(compression)相當重要。每天看學長埋首在資料的壓縮上,只要比別人的方法節省幾個bit,就可以樂翻天,準備寫論文發表。有一天,我跟教授說:「我們每天在實驗室為這些bit斤斤計較,以後進入社會,一定會成為很節儉的人」。

字型美觀

如果你研究一下TrueType字型的glyph,你會發現,大多數的中文是以「筆畫外框」來描述,但英文字型是以「視覺外框」來描述。例如,加號(+)英文字型的外框描述是一氣呵成,只需要一個figure;但是大多數中文字型的「十」卻是兩個figure,一個描述「豎」、一個描述「橫」,在豎與橫的交界處,可能會發生問題。許多軟體在顯示中文字時,沒有處理填色的問題,所以常常會造成兩個筆畫交錯的地方反倒沒有上色,那是因為預定的Fill Rule採用Even-Odd,沒有改成Non-Zero。除非是繪圖軟體,否則一般的軟體不會允許我們更改字型的Fill Rule。我常常在夜市之類的地方,看到攤販自己用Office軟體和印表機做出來的簡易海報,「珍珠奶茶買二送一」上面大大的中文字,每個筆畫交錯的地方都沒有上色,整張海報怪異到不行,這都要怪軟體。

中英文字夾雜出現時,許多軟體並沒有注意到兩者之間要有空格才美觀。MS-Word有注意到這一點,但是許多排版軟體沒有注意到這一點。所以我之前在出版社工作時,我們必須先把稿件中,英文和中文的交界處加上空白,然後才交給排版。幸好我們不必手動加空格,而是寫了一個簡單的程式來作這件事。

有一些軟體(包括Acrobat Reader和早期的Java),不是使用OS的API來繪製中文,而是取出自行檔案中的glyph資料自行繪製(附帶一提,這些程式由於沒有使用Windows顯示文字的API,所以像譯點通這類API hook的程式就會無法偵測出游標位置的文字)。這個時候,很容易就會忽略了每個字的「hint」,當字體很小時,有些筆畫可能會消失(比方說Times New Roman字型的e,中間的橫線會消失,看起來很像c)。不過這不是中文字型的問題,這是所有字型都會遇到的問題。

繁體中文字的筆畫可能相當多,如果字體很小,筆畫又不適當縮減,在螢幕上很可能會呈現一團黑,比方說,在Big-5字集中,筆畫最多的一個字是「龘」,也就是將「品」這個字的每個「口」都用「龍」取代。

有些西方的字型變化,套用到中文是不恰當的,最明顯的例子是:中文字不該出現斜體字。英文字加上斜體,可以吸引注意,但中文字加上斜體,只會讓中文字變得相當難以辨識,但許多人似乎都沒有意識到這一點。

中文輸入

以前我的美國籍英文老師看到我輸入中文時,他嘖嘖稱奇。中文字有上萬個,但鍵盤只有約100顆按鍵,對於許多不知道何謂IME(Input Method Manager)的西方人來說,如何輸入中文字,一直是一個神秘難解的謎團。

想輸入CJK(中日韓)文字,必須利用IME進行字的組合。常見的輸入法包括鍵盤、手寫、語音。微軟的鍵盤輸入法越來越好,我個人認為微軟新注音輸入法的品質,已經比一家號稱「自然就是美」的輸入法更好用了(至少新注音的錯字比較少)。我認為微軟語音輸入法的品質也快要趕上IBM,手寫輸入法的辨識率也相當高。經過數十年來的研發,中文輸入法已經不再是個重要的問題了。

甚至再這樣發展下去,中文的語音輸入法或許可以超越英文的語音輸入法,中文語音的辨識應該比英文更容易,因為除了「兒化字」之外,中文幾乎都是一個字一個音節,而英文字,連斷字都會有問題,例如「I Scream」和「Ice Cream」的發音是一樣的。雖然現在的中文語音輸入法已經算很實用。但是,對於大量輸入文字的作家,以及辦公室的人來說,還是打字比較實際。我曾經在翻譯一本書的期間,使用語音輸入法,當時我每天喋喋不休,嘴巴很痠,喉嚨很渴,這些是我事先沒預料到的,我認為語音輸入法廠商應該要在產品上加註警語,提醒消費者長時間使用,可能有口渴、嘴痠的症狀。於是,沒多久,我又走回鍵盤輸入的老路。

至於手寫輸入,速度太慢,恐怕只有在掌上裝置等不方便使用鍵盤的地方,才適合將就著使用。以剛剛提到的「龘」(三個龍)這個字來說,筆畫是48畫,假設寫3筆畫需要1秒,那麼寫出這個字就需要16秒的時間,加上寫完後停頓讓電腦辨識的時間,我們需要18秒的時間才能輸入這個字。如果講話連珠砲似的張小燕用語音輸入法,或者像莫札特這種手指頭特別靈活的神童用鍵盤輸入法,恐怕18秒的時間已經足以讓他們寫出一篇作文了。

IME,是CJK獨有的特色,但是很少有程式會好好使用它。有時候,不希望IME出現的時候,IME卻一直跳出來干擾你。如果你是軟體開發者,我建議你可以去看看IME相關的API,Flex和.NET都有這樣的API,如果這些API沒有你要的功能,你可以直接呼叫Win32的IME相關API。最近Windows平臺開始提供整合各種輸入介面的API:Text Service Framework,也值得參考。

中文造字

有許多怪異的中文字,只會出現在人的名字中。而且很可能造了這個字,就只給某一個人用,只要這個人一掛掉,這個字就再也不會有人用了。武則天就創立了不少怪字,其中最有名的是「曌」(上「明」下「空」),人家是女皇帝,我們拿她沒輒,只好眼睜睜地看她胡搞。如果生長於現代,我會幫武姑娘寫推薦信,請她到Unicode.org上班,一方面可以借重她的長才,二方面可以讓Unicode.org的老闆叫她收斂一點。

為什麼名字中會出現這麼多的怪字,那是因為中國人是很迷信的民族,連名字都是迷信的一環。孩子出生了,為了他的命運著想,會去找大師命名,大師說:「這個孩子的生肖和出生時辰缺『龍』,所以名字中要多寫幾個『龍』;天格和地格的筆畫加總必須為質數,長大以後才能成為傑出的科學家。」然後這個大師會在紅紙上用毛筆寫一個名字給你,很可能名字中的字是不存在的,新的字就被創立了。早期沒有電腦化,所以姓名的登記都是用書寫的方式,所以隨便創造的字,也可以在戶政事務所登記成功。

Unicode有大量奇特的中文字,我常常懷疑,這些字的使用頻率,一年有沒有到達一次。但是這些奇特的字,有些是古書上的字,不見得沒有存在的必要。幸好Unicode有組字功能,例如,假設武姑娘想建立「曌」這個字,但是Unicode不存在這個字,她不用跺腳插腰發姑娘脾氣,可以直接用三個Unicode的code point來表示「曌」,第一個code point表示「這個字是由上下兩個部分所組成」,第二個code point表示「上面部分是明」,第三個code point表示「下面部分是空」。這種造字方式可以套疊(nested),所以可以造出相當複雜的字。

但是先別興奮,「中文組字」雖然是Unicode的標準,但目前Windows不支援,所以你無法在Windows上面看到自己造出來的字。(但是我最近用REBOL寫的程式不使用OS的文字輸出,而是用自己的文字輸出引擎,有支援中文組字。)

中文比對

中文字的比對也會遇到問題。單純地比對code-point往往不夠,例如「峯」與「峰」的Unicode code-point雖然不一樣,但是這兩個字是異體字。如果最後決定將異體字視為完全不同的字,但是同一個字也可能會有不同的編碼。例如「曌」,可以是1個Unicode code-point,也可以是3個code-point(上下、明、空),也可以是五個code-point(上下、左右、日、月、空)。

儘管中文字的比對不再有問題,我們還是會遇到中文字排序的問題。目前繁體中文排序似乎都是照筆畫排序。Big-5分成常用字和次常用字,這兩部分各自都是以筆畫順序排序。所以只要照Big-5編碼次序排序,就等於依照中文筆畫次序排序。但是如果排序的字中,同時有常用和次常用字,那麼就不成立了。

中文字的排序,除了筆畫,應該也可以增加發音和部首,如果是這樣,恐怕每個字都必須建立形音義的資料庫。這似乎是中文比對和排序的唯一長久解決之道。

能比對中文,不見得就能正確搜尋。比方說,現在許多網站的網頁伺服器會安裝servlet,在將網頁送給client之前,會先讓servlet程式剖析過,遇到一些股票上市的公司,就加上超連結,連到該公司的股價網站。例如:文章中如果提到IBM,則在IBM的文字處加上超連結。這種應用遇到中文,往往會嚴重誤判。

比方說,文章中提到「完成祖國統一大業」,或者「三民 主義統一中國」,這裡的「統一」會被加上超連結,連結到生產速食麵(方便麵)的統一企業。統一企業和兩岸統一與否,其實一點關係都沒有。

上面的例子還算「斷字正確」,下面的例子則是斷字錯誤:「看書包準睡著」,和「書包」沒關係,所以如果連到書包的購物網站,就會貽笑大方。

我常常在看「聯合新聞網」時,發現他們的網頁就有這個問題,特別喜歡把「花」連到花卉的購物網站,所以不管文章中提到「花」費驚人、傳統豆「花」、老眼昏「花」或者歌仔戲天后楊麗「花」,通通會連到花卉的網站。我要幫楊麗花澄清一下,楊麗花不是一種花,她不賣花,也早就過了「十八姑娘一朵花」,或「女人四十一枝花」的年紀,她和「花」一點關係都沒有。

簡繁體轉換

臺灣海峽兩岸分別使用簡體和繁體(正體)中文,常常需要進行簡繁體的轉換,是透過對照表的方式。如果沒能解決剛才提到的「中文比對」問題,簡繁體轉換就可能會出問題。

除此之外,簡體字由於簡化過,所以有一些字被消滅了。例如在臺灣,「后」只做皇后的意思,但是在大陸,也具有「後」面的意思。這會使得簡繁體文件轉換之後出現失真(distortion)的狀況。

如果你有一份繁體中文文件,將它轉成簡體中文,再轉回繁體中文,你會發現文件可能失真了,我就遇過這樣的例子,我用繁體中文寫了一篇技術文章提供給大陸的雜誌發表,我自行用MS-Word的簡繁體轉換功能,將文章轉成簡體中文,再寄給大陸。後來我找不到繁體中文稿件,於是我用簡體版本的稿件,搭配MS-Word的簡繁體轉換功能,將文章轉換成繁體中文,然後就交出去給臺灣的網站發表,結果錯字一堆。我印象最深刻的是「咸」這個字。當時我的繁體中文句子是「一般咸認為這是很嚴重的問題」,化成簡體中文之後,「咸」還是「咸」;再化成繁中之後,「咸」卻變成「鹹」。

雙向文字

不過,再怎麼抱怨許多IT技術對中文的支援度不好,至少我們可以慶幸的是,我們還比阿拉伯文和希伯來文的使用者幸運。由於CJK都算是資訊大國,所以近幾年的標準都會考慮到CJK,且由於CJK都可以用「由左至右」書寫,所以可以和西方語言相容。

阿拉伯文和希伯來文就不是如此了,他們的文字「必須」由右至左書寫,且某些文字可能會受到隔壁文字的影響,而改變文字外觀。當這些「由右至左」的文字,混雜「由左至右」的西方文字時,就是「雙向文字」(bi-directional text)。

許多軟體(包括Ultra Editor)都不支援雙向文字,真正有支援雙向文字的軟體比例不高。雙向文字的演算法相當複雜,為了要讓REBOL程式支援雙向文字,我花了好幾天才把Unicode Annex #9的演算法看懂。

雖然,現在的IT中文環境還有改善的空間,但是這二、三十年來,我看著IT中文環境在大家的努力之下,確實是有長遠的進步,特別是在進入網路時代之後,更是進步神速,現在已經可以說是到了品嚐果實的時期了。

不只中文,每一個語言都是一段源遠流長的文化,在電腦技術與標準上看到這些文化的融合與保存,這不啻也是資訊科技(IT)對人類文化的一種貢獻。