新聞中心

EEPW首頁 > 嵌入式系統(tǒng) > 設計應用 > UNICODE,GBK,UTF-8區(qū)別

UNICODE,GBK,UTF-8區(qū)別

作者: 時間:2011-03-30 來源:網(wǎng)絡 收藏

4、UTF編碼

  就是以8位為單元對UCS進行編碼。從UCS-2到的編碼方式如下:

  UCS-2編碼(16進制) 字節(jié)流(二進制)

  0000 - 007F 0xxxxxxx

  0080 - 07FF 110xxxxx 10xxxxxx

  0800 - FFFF 1110xxxx 10xxxxxx 10xxxxxx

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

  讀者可以用記事本測試一下我們的編碼是否正確。需要注意,UltraEdit在打開utf-8編碼的文本文件時會自動轉換為UTF-16,可能產(chǎn)生混淆。你可以在設置中關掉這個選項。更好的工具是Hex Workshop。

  UTF-16以16位為單元對UCS進行編碼。對于小于0x10000的UCS碼,UTF-16編碼就等于UCS碼對應的16位無符號整數(shù)。對于不小于0x10000的UCS碼,定義了一個算法。不過由于實際使用的UCS2,或者UCS4的BMP必然小于0x10000,所以就目前而言,可以認為UTF-16和UCS-2基本相同。但UCS-2只是一個編碼方案,UTF-16卻要用于實際的傳輸,所以就不得不考慮字節(jié)序的問題。

  5、UTF的字節(jié)序和BOM

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

  Unicode規(guī)范中推薦的標記字節(jié)順序的方法是BOM。BOM不是“Bill Of Material”的BOM表,而是Byte order Mark。BOM是一個有點小聰明的想法:

  在UCS編碼中有一個叫做ZERO WIDTH NO-BREAK SPACE的字符,它的編碼是FEFF。而FFFE在UCS中是不存在的字符,所以不應該出現(xiàn)在實際傳輸中。UCS規(guī)范建議我們在傳輸字節(jié)流前,先傳輸字符ZERO WIDTH NO-BREAK SPACE。

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

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

  Windows就是使用BOM來標記文本文件的編碼方式的。

  6、進一步的參考資料

  本文主要參考的資料是 Short overview of ISO-IEC 10646 and Unicode (http://www.nada.kth.se/i18n/ucs/unicode-iso10646-oview.html)。

  我還找了兩篇看上去不錯的資料,不過因為我開始的疑問都找到了答案,所以就沒有看:

  Understanding Unicode A general introduction to the Unicode Standard (http://scripts.sil.org/cms/scripts/page.php?site_id=nrsiitem_id=IWS-Chapter04a)

  Character set encoding basics Understanding character set encodings and legacy encodings (http://scripts.sil.org/cms/scripts/page.php?site_id=nrsiitem_id=IWS-Chapter03)

  我寫過UTF-8、UCS-2、相互轉換的軟件包,包括使用Windows API和不使用Windows API的版本。以后有時間的話,我會整理一下放到我的個人主頁上(http://fmddlmyy.home4u.china.com)。

  我是想清楚所有問題后才開始寫這篇文章的,原以為一會兒就能寫好。沒想到考慮措辭和查證細節(jié)花費了很長時間,竟然從下午1:30寫到9:00。希望有讀者能從中受益。

  附錄1 再說說區(qū)位碼、GB2312、內(nèi)碼和代碼頁

  有的朋友對文章中這句話還有疑問:

  “GB2312的原文還是區(qū)位碼,從區(qū)位碼到內(nèi)碼,需要在高字節(jié)和低字節(jié)上分別加上A0。”

  我再詳細解釋一下:

  “GB2312的原文”是指國家1980年的一個標準《中華人民共和國國家標準 信息交換用漢字編碼字符集 基本集 GB 2312-80》。這個標準用兩個數(shù)來編碼漢字和中文符號。第一個數(shù)稱為“區(qū)”,第二個數(shù)稱為“位”。所以也稱為區(qū)位碼。1-9區(qū)是中文符號,16-55區(qū)是一級漢字,56-87區(qū)是二級漢字?,F(xiàn)在Windows也還有區(qū)位輸入法,例如輸入1601得到“啊”。(這個區(qū)位輸入法可以自動識別16進制的GB2312和10進制的區(qū)位碼,也就是說輸入B0A1同樣會得到“啊”。)

  內(nèi)碼是指操作系統(tǒng)內(nèi)部的字符編碼。早期操作系統(tǒng)的內(nèi)碼是與語言相關的?,F(xiàn)在的Windows在系統(tǒng)內(nèi)部支持Unicode,然后用代碼頁適應各種語言,“內(nèi)碼”的概念就比較模糊了。微軟一般將缺省代碼頁指定的編碼說成是內(nèi)碼。

  內(nèi)碼這個詞匯,并沒有什么官方的定義,代碼頁也只是微軟這個公司的叫法。作為程序員,我們只要知道它們是什么東西,沒有必要過多地考證這些名詞。

  所謂代碼頁(code page)就是針對一種語言文字的字符編碼。例如的code page是CP936,BIG5的code page是CP950,GB2312的code page是CP20936。

  Windows中有缺省代碼頁的概念,即缺省用什么編碼來解釋字符。例如Windows的記事本打開了一個文本文件,里面的內(nèi)容是字節(jié)流:BA、BA、D7、D6。Windows應該去怎么解釋它呢?

  是按照Unicode編碼解釋、還是按照解釋、還是按照BIG5解釋,還是按照ISO8859-1去解釋?如果按GBK去解釋,就會得到“漢字”兩個字。按照其它編碼解釋,可能找不到對應的字符,也可能找到錯誤的字符。所謂“錯誤”是指與文本作者的本意不符,這時就產(chǎn)生了亂碼。

  答案是Windows按照當前的缺省代碼頁去解釋文本文件里的字節(jié)流。缺省代碼頁可以通過控制面板的區(qū)域選項設置。記事本的另存為中有一項ANSI,其實就是按照缺省代碼頁的編碼方法保存。

  Windows的內(nèi)碼是Unicode,它在技術上可以同時支持多個代碼頁。只要文件能說明自己使用什么編碼,用戶又安裝了對應的代碼頁,Windows就能正確顯示,例如在HTML文件中就可以指定charset。

  有的HTML文件作者,特別是英文作者,認為世界上所有人都使用英文,在文件中不指定charset。如果他使用了0x80-0xff之間的字符,中文Windows又按照缺省的GBK去解釋,就會出現(xiàn)亂碼。這時只要在這個html文件中加上指定charset的語句,例如:

  如果原作者使用的代碼頁和ISO8859-1兼容,就不會出現(xiàn)亂碼了。

  再說區(qū)位碼,啊的區(qū)位碼是1601,寫成16進制是0x10,0x01。這和計算機廣泛使用的ASCII編碼沖突。為了兼容00-7f的ASCII編碼,我們在區(qū)位碼的高、低字節(jié)上分別加上A0。這樣“啊”的編碼就成為B0A1。我們將加過兩個A0的編碼也稱為GB2312編碼,雖然GB2312的原文根本沒提到這一點。


上一頁 1 2 下一頁

評論


相關推薦

技術專區(qū)

關閉