GBK,UTF-8,和ISO8859-1之間的編碼與解碼

原文鏈接:xiongchao2011的博客

Unicode、UTF-8 和 ISO8859-1到底有什麼區別

將以"中文"兩個字爲例,經查表可以知道其GB2312編碼是"d6d0 cec4",Unicode編碼爲"4e2d 6587",UTF編碼就是"e4b8ad e69687"。注意,
這兩個字沒有iso8859-1編碼,但可以用iso8859-1編碼來"表示"。 

2. 編碼基本知識 

最早的編碼是iso8859-1,和ascii編碼相似。但爲了方便表示各種各樣的語言,逐漸出現了很多標準編碼,重要的有如下幾個。 

2.1. iso8859-1 通常叫做Latin-1

屬於單字節編碼,最多能表示的字符範圍是0-255,應用於英文系列。比如,字母a的編碼爲0x61=97。 

很明顯,iso8859-1編碼表示的字符範圍很窄,無法表示中文字符。但是,由於是單字節編碼,和計算機最基礎的表示單位一致,所以很多時候,
仍舊使用iso8859-1編碼來表示。而且在很多協議上,默認使用該編碼。比如,雖然"中文"兩個字不存在iso8859-1編碼,以gb2312編碼爲例,應
該是"d6d0 cec4"兩個字符,使用iso8859-1編碼的時候則將它拆開爲4個字節來表示:"d6 d0 ce c4"(事實上,在進行存儲的時候,也是以字節爲
單位處理的)。而如果是UTF編碼,則是6個字節"e4 b8 ad e6 96 87"。很明顯,這種表示方法還需要以另一種編碼爲基礎。 

2.2. GB2312/GBK 

這就是漢子的國標碼,專門用來表示漢字,是雙字節編碼,而英文字母和iso8859-1一致(兼容iso8859-1編碼)。其中gbk編碼能夠用來同時表示
繁體字和簡體字,而gb2312只能表示簡體字,gbk是兼容gb2312編碼的。 

2.3. unicode 

這是最統一的編碼,可以用來表示所有語言的字符,而且是定長雙字節(也有四字節的)編碼,包括英文字母在內。所以可以說它是不兼容iso8859-1編
碼的,也不兼容任何編碼。不過,相對於iso8859-1編碼來說,uniocode編碼只是在前面增加了一個0字節,比如字母a爲"00 61"。 

需要說明的是,定長編碼便於計算機處理(注意GB2312/GBK不是定長編碼),而unicode又可以用來表示所有字符,所以在很多軟件內部是使用unicode
編碼來處理的,比如Java。 

2.4. UTF 

考慮到unicode編碼不兼容iso8859-1編碼,而且容易佔用更多的空間:因爲對於英文字母,unicode也需要兩個字節來表示。所以unicode不便於傳輸和存
。因此而產生了utf編碼,utf編碼兼容iso8859-1編碼,同時也可以用來表示所有語言的字符,不過,utf編碼是不定長編碼,每一個字符的長度從1-6個字
節不等。另外,utf編碼自帶簡單的校驗功能。一般來講,英文字母都是用一個字節表示,而漢字使用三個字節。 

注意,雖然說utf是爲了使用更少的空間而使用的,但那只是相對於unicode編碼來說,如果已經知道是漢字,則使用GB2312/GBK無疑是最節省的。不過另
一方面,值得說明的是,雖然utf編碼對漢字使用3個字節,但即使對於漢字網頁,utf編碼也會比unicode編碼節省,因爲網頁中包含了很多的英文字符。 

3. java對字符的處理 

在java應用軟件中,會有多處涉及到字符集編碼,有些地方需要進行正確的設置,有些地方需要進行一定程度的處理。 

3.1. getBytes(charset) 

這是java字符串處理的一個標準函數,其作用是將字符串所表示的字符按照charset編碼,並以字節方式表示。注意字符串在java內存中總是按unicode編碼
存儲的。比如"中文",正常情況下(即沒有錯誤的時候)存儲爲"4e2d 6587",如果charset爲"gbk",則被編碼爲"d6d0 cec4",然後返回字節"d6 d0 ce c4"。
如果charset爲"utf8"則最後是"e4 b8 ad e6 96 87"。如果是"iso8859-1",則由於無法編碼,最後返回 "3f 3f"(兩個問號)。 

3.2. new String(charset) 

這是java字符串處理的另一個標準函數,和上一個函數的作用相反,將字節數組按照charset編碼進行組合識別,最後轉換爲unicode存儲。參考上述getBytes
的例子,"gbk" 和"utf8"都可以得出正確的結果"4e2d 6587",但iso8859-1最後變成了"003f 003f"(兩個問號)。 

因爲utf8可以用來表示/編碼所有字符,所以new String( str.getBytes( "utf8" ), "utf8" ) === str,即完全可逆。 

3.3. setCharacterEncoding() 

該函數用來設置http請求或者相應的編碼。 

對於request,是指提交內容的編碼,指定後可以通過getParameter()則直接獲得正確的字符串,如果不指定,則默認使用iso8859-1編碼,需要進一步處理。
參見下述"表單輸入"。值得注意的是在執行setCharacterEncoding()之前,不能執行任何getParameter()。Java doc上說明:This method must be called prior to reading request parameters or reading input using getReader()。而且,該指定只對POST方法有效,對GET方法無效。分析原因,應該是在執行第一個getParameter()的時候,java將會按照編碼分析所有的提交內容,而後續的getParameter()不再進行分析,所以setCharacterEncoding()無效。而對於GET方法提交表單是,提交的內容在URL中,一開始就已經按照編碼分析所有的提交內容,setCharacterEncoding()自然就無效。

4.iso-8859-1是JAVA網絡傳輸使用的標準 字符集,而gb2312是標準中文字符集,當你作出提交表單等需要網絡傳輸的操作的時候,就需要把 iso-8859-1轉換爲gb2312字符集顯示,否則如果按瀏覽器的gb2312格式來解釋iso-8859-1字符集的話,由於2者不兼容,所以會 是亂碼.

最後來看一個編碼的例子:

[java] view plain copy
 print?
  1. String s = "你好";  
  2.   
  3. // 編碼  
  4. byte[] utf = s.getBytes("utf-8");  
  5. byte[] gbk = s.getBytes("gbk");  
  6.   
  7. System.out.println("utf-8編碼:" + Arrays.toString(utf)); // [-28, -67, -96, -27, -91, -67]  6個字節  
  8. System.out.println("gbk編碼:" + Arrays.toString(gbk)); // [-60, -29, -70, -61]<span style="white-space:pre">  </span>4個字節  
  9.   
  10. // 解碼  
  11. String s1 = new String(utf, "utf-8"); // 你好  
  12. String s2 = new String(utf, "gbk");// gbk解碼:浣犲ソ gbk用2個字節解碼,所以會多一個字符  
  13. String s3 = new String(gbk, "utf-8");// gbk用utf-8解碼:??? <span style="white-space:pre">  </span>utf-8解碼需要6個字節  
  14.   
  15. System.out.println("--------------------");  
  16. System.out.println("utf-8解碼:" + s1);  
  17. System.out.println("gbk解碼:" + s2);  
  18. System.out.println("gbk用utf-8解碼:" + s3);  
  19. System.out.println("---------------------");  
  20.   
  21. System.out.println("用utf-8編碼回去");  
  22.   
  23. s3 = new String(s3.getBytes("utf-8"), "gbk");  // 錕斤拷錕?   gbk用utf-8解碼後無法編回去  
  24.   
  25. System.out.println(s3);  
規律:

 utf-8編碼可以用gbk和iso8859-1解碼後編回去
gbk編碼後只能用iso8859-1解碼後編回去

在JSP頁面獲取表單的值時會出現亂碼,有兩種解決方法:

一種是在調用getParameter之前通過request.setCharacterEncoding設置字符編碼,另一種是調用new String(str.getBytes("iso8859-1"), "UTF-8");編碼後解碼,這兩種方法都可以得到正確的結果

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章