1.從Txt看起
新建一個Txt文件,輸入字符“ab早”,選擇菜單另存爲,此時出現4個選項,見圖1。
圖1
這是四種不同的編碼。
分別以這四種編碼來保存文件,並用二進制編輯器查看生成的文件,可以得到如下的結果。
編碼方式 | 用十六進制表示的文件內容 |
ANSI | |
Unicode | |
Unicode big endian | |
UTF-8 |
圖2
(一)ANSI
ANSI編碼應該算是一套很龐大的體系。簡體中文GB2312,繁體中文BIG5等都只是ANSI的一個代碼頁。
什麼是代碼頁呢?打開Windows的控制面板->區域和語言,可以看到如下的選項。
圖3
這裏面每一個選項都是一個代碼頁。
也可以這麼說,如果系統語言選擇了中文(簡體,中國),那麼該系統中ANSI就代表GB2312編碼。同理,選擇中文(繁體,臺灣),那麼ANSI就代表BIG5編碼。
做個小實驗驗證一下。在簡體中文環境下,新建一個Txt文件輸入“ab早”,另存爲ANSI編碼。切換語言環境爲繁體中文(前提是裝過對應的語言包),系統要求重啓,確定。重啓之後,打開之前保存的Txt文件。顯示出來的內容變成了“ab婌”。‘早’的GB2312編碼是D4E7,‘婌’的BIG5編碼也是D4E7。這就驗證了之前所說的,同樣的數據用ANSI編碼,在不同的系統語言環境下,被解釋成了不同的字符。
另外,不論是ANSI編碼的哪個代碼頁,都是兼容ASCII碼的。也就是說,對於ASCII碼中的128個字符,在ANSI中也是用一個字節表示。其它字符都是用兩個字節表示的,並且這兩個字節都是大於0x7F的。
(二)Unicode
Unicode可以編碼大部分語言的大部分字符。在網上找資料的時候,有個問題一直在困擾着我。照理說,現在Unicode的編碼範圍是0-0x10FFFF,這已經是3個字節了,我疑惑的是爲什麼Unicode字符統一都是兩個字節呢?
繼續找資料。我得出的結論是此處的Unicode其實是Utf-16。好吧,大膽猜測,接下來還要小心求證。
求證之前,先來說說什麼是Utf-8,Utf-16,Utf-32(下面簡稱Utf-x)。Unicode只規定了從數字到字符的對應關係,並沒有規定具體的實現方法。因此Utf-x其實是Unicode的具體實現,當然也可以稱爲Unicode的再編碼。從Unicode到Utf-x是有具體的映射關係的,而且是有規律的映射關係,可以用一個簡單的函數來轉換。
開始求證吧。從Unicode到Utf-x的詳細映射方法,可點擊最下面的鏈接(Unicode)查看。這裏簡要說說Utf-16是怎麼映射的。Unicode編碼共有21位,當高5位爲0時,Unicode編碼和Utf-16相同,此時在Utf-16編碼中,一個字符佔2個字節。當高5位不爲0時,Unicode編碼經過映射變成了4個字節的Utf-16編碼,顯然這時一個字符佔4個字節。
先來驗證高5位爲0時的情況。之前已經試過,在Txt文件中輸入‘ab早’,另存爲UNICODE格式,用二進制編輯器查看,發現‘早’的編碼是“E965”。在Unicode詳細編碼表中查找(下有鏈接),要注意這裏存儲方式是小尾的,也就是說‘早’的真正編碼是65E9。
結果我就不貼了,‘早’字確實在編碼表的那個位置。
再來驗證高5位不爲0時的情況。先找個Unicode編碼大於0xFFFF的字符(有些範圍內的字符顯示出來都是方框,估計我的電腦上就沒有這種字符)。用來做實驗的字符見下圖。
圖4
選用編碼爲0x20001的那個字符(Word上顯示不了這個字符,Txt上面倒是可以)。複製這個字符到Txt中,另存爲Unicode,再用二進制編輯器打開。結果如下:
圖5
編碼後的長度是4個字節,這個已經對上了,再看看具體的值對不對。算吧!
1.U= 0x20001
2.U’= U – 0x10000 = 0x10001 = 0001 0000 0000 0000 0001
3.Utf-16= 1101 1000 0100 0000 1101 1100 0000 0001 = 0xD840DC01
4.考慮到以小尾方式存儲 Utf-16’ = 0x40D801DC
5.是不是和上圖中的數字對上了啊!
現在大體上已經可以確認Txt中這個所謂的Unicode其實就是Utf-16,或者至少是一個和Utf-16兼容的編碼。
最後說說FFFE和FEFF。可以看到當將Txt保存爲Unicode編碼的時候,不論大小尾,在正式字符編碼開始之前,都會有FFFE或FEFF。這個是用來表示字節序的,FFFE是小尾字節序,FEFF是大尾字節序。
(三)Unicode big endian
除了字節序採用大尾之外,其它的都和Unicode一樣。
(四)UTF-8
UTF-8也是UNICODE編碼的一個具體實現方式。UTF-8的特點是變長編碼(1~4個字節),對於0x00~0x7F之間的編碼與ASCII碼完全相同,而漢字一般情況下編碼長度是3個字節。那麼下面動手求求‘早’字的UTF-8編碼是多少吧!
1.U = 0x65E9 = 01100101 1110 1001
2.套用第三個模板
3.Utf-8 = 11100110 1001 0111 1010 1001 = 0xE697A9
4.對照圖 2,結果是對的。
此外可以發現,UTF-8格式的文件,在正式編碼之前也有個標記,EFBBBF,這個是UTF-8文件頭,用來告訴別人接下來的數據是UTF-8編碼。
相關資料:
http://blog.csdn.net/xiongxiao/article/details/3741731 ----- 多種編碼
http://baike.baidu.com/link?url=yxnWqjaIlBpMMenb3gmQtX5thFAds4ysiSgE-HS-lS8qwpsYNYrsdRLM8zrEKXou ----- 代碼頁
http://baike.baidu.com/link?url=Op9QHQGnv97slgXaB7YpEsEo_GW3KRfm-Nf202xELyCpcKHacc5xKUvlqvB2Hjlu ----- Unicode
http://zh.wikibooks.org/wiki/Unicode/0000-0FFF ----- Unicode詳細編碼表
----- GB2312編碼表
----- BIG5編碼表