Ads 468x60px

##EasyReadMore##

13 10月, 2017

Unicode編碼

0、big endian和little endian

big endian和little endian是CPU處理多字元數的不同方式。例如「漢」字的
Unicode編碼是6C49。那麼寫到文件裡時,究竟是將6C寫在前面,還是將49寫在前面?如果將6C寫在前面,就是big endian。如果將49寫在前面,就是little endian。

「endian」這個詞出自《格列佛遊記》。小人國的內戰就源於吃雞蛋時是究竟從大頭(Big-Endian)敲開還是從小頭(Little-Endian)敲開,由此曾發生過六次叛亂,一個皇帝送了命,另一個丟了王位。

我們一般將endian翻譯成「字元序」,將big endian和little endian稱作「大尾」和「小尾」。

1、字串編碼、內碼,順帶介紹漢字編碼
字串必須編碼後才能被電腦處理。電腦使用的預設編碼方式就是電腦的內碼。早期的電腦使用7位的ASCII編碼,為了處理漢字,程序員設計了用於簡體中文的GB2312和用於繁體中文的big5。

GB2312(1980年)一共收錄了744灌水限制符,包括6763個漢字和682個其它符號。漢字區的內碼範圍高字元從B0-F7,低字元從A1-FE,佔用的碼位是72*94=6768。其中有5個空位是D7FA-D7FE。

GB2312支持的漢字太少。1995年的漢字增強規範GBK1.0收錄了21886個符號,它分為漢字區和圖形符號區。漢字區包括21003個字串。2000年的GB18030是取代GBK1.0的正式國家標準。該標準收錄了27484個漢字,同時還收錄了藏文、蒙文、維吾爾文等主要的少數民族文字。現在的PC平台必須支持GB18030,對嵌入式產品暫不作要求。所以手機、MP3一般只支持GB2312。

2、Unicode、UCS和UTF
歷史上存在兩個試圖獨立設計Unicode的組織,即國際標準化組織(ISO)和一個軟體製造商的協會(unicode.org)。ISO開發了ISO 10646項目,Unicode協會開發了Unicode項目。

在1991年前後,雙方都認識到世界不需要兩個不相容的字串集。於是它們開始合併雙方的工作成果,並為創立一個單一編碼表而協同工作。從Unicode2.0開始,Unicode項目採用了與ISO 10646-1相同的字庫和字碼。

UCS只是規定如何編碼,並沒有規定如何傳輸、儲存這個編碼。例如「漢」字的UCS編碼是6C49,我可以用4個ascii數位來傳輸、儲存這個編碼;也可以用utf-8編碼:3個連續的字元E6 B1 89來表示它。關鍵在於通信雙方都要認可。UTF-8、UTF-7、UTF-16都是被廣泛接受的方案。UTF-8的一個特別的好處是它與ISO- 8859-1完全相容。UTF是「UCS Transformation Format」的縮寫。

2.1、內碼和code page(IBM稱呼計算機的BIOS所支持的字符集編碼)

目前Windows的內核已經採用Unicode編碼,這樣在內核上可以支持全世界所有的語言文字。但是由於現有的大量程序和文件都採用了某種特定語言的編碼,例如GBK,Windows不可能不支持現有的編碼,而全部改用Unicode。

Windows使用程式碼頁(code page)來適應各個國家和地區。code page可以被理解為前面提到的內碼。GBK對應的code page是CP936。

4、UTF編碼

UTF-8就是以8位為單元對UCS進行編碼。從UCS-2到UTF-8的編碼方式如下:
UCS-2編碼(16進制) UTF-8 字元流(二進制)
0000 - 007F 0xxxxxxx
0080 - 07FF 110xxxxx 10xxxxxx
0800 - FFFF 1110xxxx 10xxxxxx 10xxxxxx

例如「漢」字的Unicode編碼是6C49。6C49在0800-FFFF之間,所以肯定要用3字元範本了:1110xxxx 10xxxxxx 10xxxxxx。將6C49寫成二進制是:0110 110001 001001, 用這個比特流依次替代範本中的x,得到:11100110 10110001 10001001,即E6 B1 89。

5、UTF的字元序和BOM

UTF-8以字元為編碼單元,沒有字元序的問題。UTF-16以兩個字元為編碼單元,在解釋一個UTF-16文本前,首先要弄清楚每個編碼單元的字元序。例如「奎」的Unicode編碼是594E,「乙」的Unicode編碼是4E59。如果我們收到UTF-16字元流「594E」,那麼這是「奎」還是「乙」?

Unicode規範中推薦的標記字元順序的方法是BOM。BOM不是「Bill Of Material」的BOM表,而是Byte Order Mark。BOM是一個有點小聰明的想法:

在UCS編碼中有一個叫做"ZERO WIDTH NO-BREAK SPACE"的字串,它的編碼是FEFF。而FFFE在UCS中是不存在的字串,所以不應該出現在實際傳輸中。UCS規範建議我們在傳輸字元流前,先傳輸字串"ZERO WIDTH NO-BREAK SPACE"。

這樣如果接收者收到FEFF,就表明這個字元流是Big-Endian的;如果收到FFFE,就表明這個字元流是Little-Endian的。因此字串"ZERO WIDTH NO-BREAK SPACE"又被稱作BOM。

UTF-8不需要BOM來表明字元順序,但可以用BOM來表明編碼方式。字串"ZERO WIDTH NO-BREAK SPACE"的UTF-8編碼是EF BB BF(讀者可以用我們前面介紹的編碼方法驗證一下)。所以如果接收者收到以EF BB BF開頭的字元流,就知道這是UTF-8編碼了。
Windows就是使用BOM來標記文本文件的編碼方式的。

談談Unicode編碼 @ 十年磨一劍 :: 痞客邦 PIXNET :: - https://goo.gl/NcY1Pc

0 意見:

張貼留言

 
Blogger Templates