寫過兩篇關於編碼的文章了,覺得本身比較瞭解編碼了呢?!測試
結果今天又結結實實的上了一課。編碼
之前轉來轉去解決的問題終歸仍是簡單的情形。即iso-8859-1轉utf-8,或者iso-8859-1轉gbk,gb2312之類。這種無損轉換,一行代碼就搞定。spa
今天遇到了gbk轉utf-8。不管怎麼轉,都是亂碼。code
1、亂碼的緣由blog
gbk的中文編碼是一個漢字用【2】個字節表示,例如漢字「內部」的gbk編碼16進制的顯示爲c4 da b2 bfutf-8
utf-8的中文編碼是一個漢字用【3】個字節表示,例如漢字「內部」的utf-8編碼16進制的顯示爲e5 86 85 e9 83 a8字符串
很顯然,gbk是沒法直接轉換成utf-8,少字節變爲多字節,誰知道缺乏的字節是什麼啊?!get
2、轉換的辦法io
有辦法實現「有損」轉換嗎?答案是確定的。class
1.首先將gbk字符串getBytes()獲得兩個原始字節,轉換成二進制字符流,共16位。
2.根據UTF-8的漢字編碼規則,首字節以1110開頭,次字節以10開頭,第3字節以10開頭。在原始的2進制字符串中插入標誌位。最終的長度從16--->16+4+2+2=24。
3.轉換完成,實際狀況須要考慮更多因素,例如字符串是漢字和數字的混合體,須要識別處理數字。
3、不要重複發明輪子
這段代碼測試可用還很好用,須要的能夠參考。
1 public static String getUTF8StringFromGBKString(String gbkStr) { 2 try { 3 return new String(getUTF8BytesFromGBKString(gbkStr), "UTF-8"); 4 } catch (UnsupportedEncodingException e) { 5 throw new InternalError(); 6 } 7 } 8 9 public static byte[] getUTF8BytesFromGBKString(String gbkStr) { 10 int n = gbkStr.length(); 11 byte[] utfBytes = new byte[3 * n]; 12 int k = 0; 13 for (int i = 0; i < n; i++) { 14 int m = gbkStr.charAt(i); 15 if (m < 128 && m >= 0) { 16 utfBytes[k++] = (byte) m; 17 continue; 18 } 19 utfBytes[k++] = (byte) (0xe0 | (m >> 12)); 20 utfBytes[k++] = (byte) (0x80 | ((m >> 6) & 0x3f)); 21 utfBytes[k++] = (byte) (0x80 | (m & 0x3f)); 22 } 23 if (k < utfBytes.length) { 24 byte[] tmp = new byte[k]; 25 System.arraycopy(utfBytes, 0, tmp, 0, k); 26 return tmp; 27 } 28 return utfBytes; 29 }
PS:有點兒對不住原做者,找了不少代碼,一一測試,結果網頁都關閉了,若是有大神認領,我必定補充連接,並且深表感謝。