ISO-8859-1, ASCII, GB 2312, Unicode字符集解析

在編程方面常常遇到字符編碼的問題,因爲對字符集沒有一個系統的認識,老是被亂碼搞得一頭霧水,這篇博文則是對字符編碼方面的進行了一下整理,以便往後複習。在學習字符集的過程當中,我主要從字符集的(a)編碼方式,(b)佔用字節,兩個方面來進行分析的。前端

ISO-8859-1/ASCII

參考資料:ISO-8859-1編程

ISO-8859-1(Latin1)編碼是單字節編碼,向下兼容ASCII,其編碼範圍是0x00-0xFF,0x00-0x7F之間徹底和ASCII一致,0x80-0x9F之間是控制字符,0xA0-0xFF之間是文字符號。由於ISO-8859-1編碼範圍使用了單字節內的全部空間,在支持ISO-8859-1的系統中傳輸和存儲其餘任何編碼的字節流都不會被拋棄。換言之,把其餘任何編碼的字節流看成ISO-8859-1編碼看待都沒有問題。下圖爲ISO-8859-1字符集(包括ASCII字符集,圖片來自百科)的編碼表,編碼方式數組

ISO-8859-1編碼

在下面代碼中,字符串str"úù§ABD"的前三個字符因爲不在ASCII編碼範圍內,故變量asc不能還原爲源字符串。由byte數組的長度來看,ISO-8859-1和ASCII爲單字節編碼學習

 1 public static void iso(){
 2     String str = "úù§ABD";
 3     try {
 4         byte[] ch = str.getBytes("ISO-8859-1");
 5         String asc = new String(ch, "ASCII");
 6         String iso = new String(ch, "ISO-8859-1");
 7         System.out.println(str+" length:"+ch.length+" bytecode:"+byte2hex(ch)+"\nASCII:"+asc +"\nISO-8859-1:"+iso);
 8     } catch (UnsupportedEncodingException e) {
 9         // TODO Auto-generated catch block
10         e.printStackTrace();
11     }
12 }

OUTPUT:測試

úù§ABD length:6 bytecode: fa f9 a7 41 42 44
ASCII:???ABD
ISO-8859-1:úù§ABD編碼

GBK/GB2312

參考資料:GB 2312GBKurl

GB 2312標準共收錄6763個漢字,其中一級漢字3755個,二級漢字3008個;同時,GB 2312收錄了包括拉丁字母、希臘字母、日文平假名及片假名字母、俄語西裏爾字母在內的682個全角字符。GB 2312的出現,基本知足了漢字的計算機處理須要,它所收錄的漢字已經覆蓋中國大陸99.75%的使用頻率。對於人名、古漢語等方面出現的罕用字,GB 2312不能處理,這致使了後來GBK及GB 18030漢字字符集的出現。
  
   漢字區位碼:GB 2312中對所收漢字(字符)進行了「分區」處理,每區含有94個漢字/符號。每一個漢字可使用一個4位的十進制表示,稱爲區位碼,前兩位爲區碼,後兩位爲位碼。
  01-09區爲特殊符號。
  16-55區爲一級漢字,按拼音排序。
  56-87區爲二級漢字,按部首/筆畫排序。
  10-15區及88-94區則未有編碼。
  舉例來講,「啊」字是GB2312之中的第一個漢字,它的區位碼就是1601(十進制)。
   字節編碼方式:
  在使用GB2312的程序中,一般採用EUC儲存方法(分別將區碼和位碼加上0xA0),以便兼容於ASCII。
  每一個漢字及符號以兩個字節來表示。第一個字節稱爲「高位字節」(也稱「區字節)」,第二個字節稱爲「低位字節」(也稱「位字節」)。
  「高位字節」使用了0xA1-0xF7(把01-87區的區號加上0xA0),「低位字節」使用了0xA1-0xFE(把01-94加上 0xA0)。 因爲一級漢字從16區起始,漢字區的「高位字節」的範圍是0xB0-0xF7,「低位字節」的範圍是0xA1-0xFE,佔用的碼位是 72*94=6768(72個漢字分區)。其中有5個空位是D7FA-D7FE。
  以「啊」字爲例,「高位字節」:0x10(16)+0xA0=0xB0, 「低位字節」:0x01(01)+0xA0=0xA1。「啊」編碼爲0xB0A1

GBK全稱《漢字內碼擴展規範》,GBK編碼,是在GB2312-80標準基礎上的內碼擴展規範,使用了雙字節編碼方案,其編碼範圍從8140至FEFE(剔除xx7F),共23940個碼位,共收錄了21003個漢字。GBK爲對GB2312的一次擴充,其高位字節再也不要求區號加0xA0,低位字節甚至不要求首位bit爲1,這樣大大擴充了GB2312的可編碼範圍。spa

 1 public static void gb(){
 2     String str = "啊aA";
 3     byte[] ch;
 4     try {
 5         ch = str.getBytes("GB2312");
 6         System.out.println("ch length:"+ch.length+" bytecode:"+byte2hex(ch));
 7         ch = str.getBytes("GBK");
 8         System.out.println("ch length:"+ch.length+" bytecode:"+byte2hex(ch));
 9     } catch (UnsupportedEncodingException e) {
10         // TODO Auto-generated catch block
11             e.printStackTrace();
12     }
13 }

OUTPUT:.net

ch length:4 bytecode: b0 a1 61 41
ch length:4 bytecode: b0 a1 61 41code

從程序能夠看出GB2312,GBK是不定長的,漢字爲2個字節,英文字符爲一個字節。因爲表示漢字或圖形符號的「高位字節」的首個bit都爲1,而ASCII首個bit爲0,而實現了這兩種字符集對ASCII的兼容。

Unicode/UTF-8/UTF-16/UTF-32

參考資料:Unicode, UTF-8, UTF-16, UTF-32, 通用字符集

Unicode伴隨着通用字符集的標準而發展,Unicode至今仍在不斷增修,每一個新版本都加入更多新的字符。目前最新的版本爲2014年6月16日公佈的7.0.0。實際應用的Unicode版本對應於UFT-16。Unicode一般會用「U+」而後緊接着4個十六進制的數字來對應一個經常使用字符,如」U+4EA0「表明某一個字符,若須要表示更多的字符則須要使用五位或六位十六進制數,這是Unicode對字符的表示方式。

UTF(Unicode transfromation format)是Unicode的不一樣實現,這裏的實現指的是字符在計算機中的表示方式。

UTF-8是一種針對Unicode的可變長度字符編碼,它能夠用來表示Unicode標準中的任何字元,且其編碼中的第一個字節仍與ASCII兼容。下圖是字符在UTF-8中的編碼方式,UTF-8可能使用三、4或更多個字節表示一個字符。

UTF-16使用兩個字節表示經常使用的字符(碼位從U+0000至U+FFFF),對於超出U+FFFF外的字符須要4字節表示,這裏僅表示大體理解,深刻了解請查看維基百科UTF-16

UTF-32是另外一種將Unicode字符編碼的協議,對每個Unicode碼位均使用定長的4字節來表示。

 1 public static void unicode(){
 2     String str1 = "中文測試";
 3     byte[] ch;
 4     try {
 5         ch = str1.getBytes("unicode");
 6         System.out.println(str1+" length:"+ch.length+" unicode:"+byte2hex(ch));
 7         ch = str1.getBytes("utf-8");
 8         System.out.println(str1+" length:"+ch.length+" utf-8:"+byte2hex(ch));
 9         ch = str1.getBytes("utf-16");
10         System.out.println(str1+" length:"+ch.length+" utf-16:"+byte2hex(ch));
11         ch = str1.getBytes("utf-32");
12         System.out.println(str1+" length:"+ch.length+" utf-32:"+byte2hex(ch));
13         str1 = "test";
14         ch = str1.getBytes("unicode");
15         System.out.println(str1+" length:"+ch.length+" unicode:"+byte2hex(ch));
16         ch = str1.getBytes("utf-8");
17         System.out.println(str1+" length:"+ch.length+" utf-8:"+byte2hex(ch));
18         ch = str1.getBytes("utf-16");
19         System.out.println(str1+" length:"+ch.length+" utf-16:"+byte2hex(ch));
20         ch = str1.getBytes("utf-32");
21         System.out.println(str1+" length:"+ch.length+" utf-32:"+byte2hex(ch));
22     } catch (UnsupportedEncodingException e) {
23         // TODO Auto-generated catch block
24         e.printStackTrace();
25     }
26 }

OUTPUT:

中文測試 length:10 unicode: fe ff 4e 2d 65 87 6d 4b 8b d5
中文測試 length:12 utf-8: e4 b8 ad e6 96 87 e6 b5 8b e8 af 95
中文測試 length:10 utf-16: fe ff 4e 2d 65 87 6d 4b 8b d5
中文測試 length:16 utf-32: 00 00 4e 2d 00 00 65 87 00 00 6d 4b 00 00 8b d5
test length:10 unicode: fe ff 00 74 00 65 00 73 00 74
test length:4 utf-8: 74 65 73 74
test length:10 utf-16: fe ff 00 74 00 65 00 73 00 74
test length:16 utf-32: 00 00 00 74 00 00 00 65 00 00 00 73 00 00 00 74

從實驗結果來看,UTF-8使用3個字節表示中文字符,1字節表示英文字符。UTF-32使用4個字節來表示每一種字符。在Unicode和UTF-16用兩個字節表示中英文字符,且前端均有一個feff字節,該字節爲BOM(Byte Order Mark)表示字節讀取順序。

本文主要記錄了做者學習字符集的過程,若有錯誤,望諒解指正。想要了解下字符集的發展過程,這篇風趣的文章有所介紹:http://blog.csdn.net/aisq2008/article/details/6298170

相關文章
相關標籤/搜索