2009/03/05

中文編碼是幾個位元?

在回答這個問題前,請你先瞭解萬國碼 Unicode 的意義,及他的編碼方式。

The Joel on Software Translation Project:萬國碼

節錄:

Unicode

Unicode是個勇敢的嘗試,想用單一個字元集去涵括地球上所有合理的書寫系統,另外也要包括克林貢語等杜撰的語文。有些人誤認為Unicode只是個16位元碼,裡頭每個字都要佔16位元,所以總共有65,536個字元。事實上這並不正確。這是關於Unicode常見的誤解,所以如果你也這麼認為的話,不用難過。

事實上Unicode對字元有不一樣的想法,你必須瞭解Unicode的想法,否則是搞不懂的。

到目前為止,我們都假設一個字母會對映到某些位元,這些可以存在磁碟或記憶體中:

A -> 0100 0001

在Unicode裡一個字母是對映到一個叫code point的東西(還只是一個理論上的概念)。要如何在記憶體或是磁碟上表示code point就完全是另一回事。

在Unicode中,字母A是個精神上的觀念。它只會漂浮在天堂裡:
A

這個觀念上的A和B或者a都不一樣,不過A和A以及A都一樣。Times New Roman字型的A和Helvetica字型的A是相同的字元,但和小寫的"a"不一樣,這種想法似乎沒什麼好爭論的。不過在某些語言中,光是要決定一個字母是什麼就有得吵了。舉例來說,德文字母β究竟真正的字母還是ss(譯註:拉丁文的gei)的另一種特別寫法呢?如果字母的形狀在單字結束時會改變,改變之後要當作不同的字母嗎?希伯來文說是,阿拉伯文卻認為不是。不管如何,Unicode協會的聰明人已經在過去十年左右搞定了,雖然有一大堆政治爭論伴隨而來,不過你不用擔心。他們已經完全搞定了。 Unicode協會把所有字母系統中每一個觀念上的字母都分配一個魔術數字,這個數字的寫起來就像是:U+0645。這個魔術數字就叫一個code point。U+的意思是Unicode,數字則是用十六進位表示。U+FEC9就是阿拉拍文的字母Ain。英文字母A則是U+0041。你可以用Windows 2000/XP的charmap工具把這些數字全找出來,到Unicode網站也可以找到。

Unicode可以定義的字母數量並沒有實質限制,事實上可以超過65,536個,所以並不是所有的Unicode字母都能擠進兩個位元組裡,不過反正那本來就是個迷思。


.....
....
...

關於字元編碼最重要的一個事實

如果你完全不記得我剛說的東西,請至少記住一件超級重要的事實。光有字串卻不知道編碼方式是不行的。你不能再把頭埋在沙裡假裝「純」文字就是ASCII。
根本就沒有純文字這種東西。

假設你有一個字串,不管是在記憶體或在檔案還是在電郵訊息裡,你都必須知道字串用的編碼方式,才能正確解譯出來並呈現給使用者。

「我的網站都是亂碼」或「她看不到我用重音符號寫的電郵」之類的笨問題,幾乎全部都是因為某位天真的程式師不瞭解一個單純的事實:如果不知道某個字串的編碼方式是UTF-8還是ASCII還是ISO 8859-1 (Latin 1)還是Windows 1252 (西歐),根本不可能正確顯示出來,甚至連在哪結束可能都找不到。大於127的code point有上百種編碼方式,連猜都猜不到。

我們要如何保存某個字串的編碼資訊呢?好吧,是有一些標準方法可以用。以電子郵件來說,郵件表頭應該會有一個字串:

Content-Type: text/plain; charset="UTF-8"

如果是網頁的話,最原始的想法是在網頁之外,再讓web伺服器傳回一個類似的Content-Type http header。不是放在HTML裡面,而是在傳HTML網頁之前先送的header。

這樣做會有問題。假設你有一個很大的web伺服器,很多使用各種語言的人在裡面放了很多網站和網頁,所有網頁的編碼方式都是由微軟FrontPage自動產生。Web伺服器本身其實並不知道各個檔案的編碼方式,所以也沒法子傳出正確的Content-Type header。

利用某些特別的tag把HTML檔案的Content-Type放在HTML檔案裡比較方便。當然這會讓純粹主義者抓狂...你怎麼能在不知道編碼方式之前讀HTML檔案呢!?幸運的是,幾乎所有編碼方式由32到127的字元都是一樣的,所以不需用到怪字母就能在HTML網頁取到這些資訊:





不過這個meta tag一定得放在段落非常前面的地方。因為網頁瀏覽器一看到這個tag就會停止分析,然後改用你指定的編碼方式重新解譯整個網頁。

如果瀏覽器在http header或meta tag都找不到Content-Type時會怎麼做呢?Internet Explorer會做一件很有趣的事:它會依據各位元組在各種常見語言編碼中出現的頻率,猜測網頁所用的語言及編碼方式。由於各種舊的8位元頁碼通常把該國的字母放在128到255範圍內不同的位置,而各種人類語言的字母使用頻率都有不同的分佈特性,所以這種做法的確有機會成功。這種做法真的很奇怪,不過似乎的確很有效。效果好到那些天真到不知道要用Content-Type header的網頁製作者根本不知道自己錯了,因為他們的網頁用瀏覽器來看時一切正常。等到某一天,當他們寫的內容不符合所用語言的字母頻率分佈時,Internet Explorer就會把它認成韓文來顯示。我認為這也證明Postel's Law中關於「發送時嚴謹,接收時寬鬆」的論點實在不是一個良好的工程原則。不管如何,當遇到這個用保加利亞文寫卻顯示成韓文(還不是有意義的韓文)的網頁時,可憐的讀者要怎麼辦呢?他會用由選單選檢視|編碼,然後嘗試各種不同的編碼(裡面有十幾種東歐語言)直到看起來對為止。不過當然是要他會這招才行,不過大多數人都不會。




沒有留言: