1. 程式人生 > >字元編碼問題之手動轉碼並不萬能

字元編碼問題之手動轉碼並不萬能

結果如下: -52 -20 
-17 -65 -67 -17 -65 -67 
錕斤拷
上面的過程與我們開頭提到的web中手動轉碼的問題非常相像。 但是,這次為什麼失敗了呢。先讓我們看看上面程式碼做了什麼。 相當於 1.首先把str通過gbk編碼得到了位元組陣列b 2.把位元組陣列b用uft8字符集解碼生成新的字元str2 3.把str2字元用utf-8字符集編碼成位元組陣列b2 (2)(3)看似可逆。 實際上是 1.首先把str通過gbk編碼得到了位元組陣列b 2.利用位元組陣列b,通過utf-8到unicode的轉換演算法生成新的字元str2 3.把字串str2利用utf-8到unicode的轉換演算法解碼生成位元組陣列b2
為什麼b的值與b2的值不同呢? 現是位元組陣列通過utf-8解碼生成字元,然後字元通過utf-8編碼生成位元組陣列。 明明是可逆的操作,為什麼不能還原.讓b2與b相等呢? 確實這種轉換演算法實際上是可逆的。 但問題出現在哪了呢? 其實大家忽略了一個細節我們的b位元組數組裡面的值是gbk編碼形式的。 把一個gbk形式的位元組流 通過utf-8到unicode轉換演算法 轉成 unicode碼。這個過程之中因為utf-8與gbk的不相容。導致了轉換過程出現了錯誤。 所以在,你想轉回來的時候,你用錯誤的結果無法轉換回來。 再來看看最開頭提到的例子:
public class Test4 {

	public static void main(String[] args) throws Exception {
		String str = "天";
		byte[] b = str.getBytes("gbk");
		show(b);
		String str2 = new String(b,"ISO8859-1");
		byte[] b2 = str2.getBytes("ISO8859-1");
		show(b2);
		System.out.println(new String(str2.getBytes("ISO8859-1"),"gbk"));
		
	}
    public static void show(byte[] b){
    	for (int i = 0; i < b.length; i++){
    		System.out.print(b[i]+ " ");
    	}
    	System.out.println();
    }

}


結果如下: -52 -20 
-52 -20 

為什麼用ISO8859-1就成功了呢?為什麼用ISO8859-1就可逆了呢? 如果詳細說會比較麻煩,你可以認為在這種操作的時候ISO8859-1和gbk的相容性比較好。 如果你覺得只說相容性這個詞太抽象的話,可以稍微這麼理解。 b[]位元組數組裡面存的是gbk編碼,如果用utf-8到unicode的轉換演算法。這個位元組數組裡面的某些位用這種演算法無法解析,於是資料就出現了錯誤,資料錯誤之後,你想轉換回來當然不行了(所謂的相容性不好)。 b[]位元組數組裡面存的是gbk編碼,如果用iso8859-1到unicode的轉換演算法。雖然位元組陣列的某些位不是標準的iso8859-1的格式,但是這種演算法仍然能按照某種方式解析,所以資料沒出現錯誤,所以你想轉換回來的時候,還能轉換回來(所謂的相容性好)。 所以說,手工轉碼不是萬能的。 最佳實踐:事先調整好傳送方與接收方的字符集,最好別手工轉碼。
以上純屬個人觀點,歡迎討論。