最開始接觸web的時候,因爲Tomcat服務器默認的URIEncoding是ISO8859-1。應該產生過中文亂碼問題,某些前輩就會告訴你,可以手動轉碼。new String(str.getBytes("IOS8859-1"),"gbk");
如果頁面編碼方式是gbk,Tomcat URIEncoding是ISO8859-1。這樣編碼再解碼,看着確實合理,而且能解決問題。但是其實手動轉碼侷限性是比較大的。
基本概念介紹編碼是幹什麼
編碼就是把字符按照規定的字符集轉換成 0 1 的字節流形式.解碼是什麼Java中的字符都是按照Unicode字符集進行編碼的。
是把相應的0 1字節流按照規定字符集轉換成相應字符的形式。
也就是說,JVM管理的內存中的,字符都是以Unicode編碼形式存在的。而非JVM的內存中,字符是以各種各樣的字符集進行編碼的,當Java程序與外界交互的時候(如I/O),就會涉及到編碼解碼問題。在Java中,不同的字符集都是以Unicode作爲橋樑相互轉換的。
- String兩個常用API原理介紹。
結果:-52 -20public static void main(String[] args) throws Exception { String str = "天"; byte[] b = str.getBytes("gbk"); show(b); } public static void show(byte[] b){ for (int i = 0; i < b.length; i++){ System.out.print( b[i] + " "); } System.out.println(); }
byte[] b = str.getBytes("gbk");
這句話的意思是把str中的字符 天 用gbk字符集進行編碼,返回編碼後的字節數組。把-51 -20的2進制的表示形式就是 天 在gbk字符集中的編碼。
內存中的操作方式如下相當於從內存中取出天字的Unicode編碼,然後利用Unicode到gbk的轉換算法,得到天字的gbk編碼
如圖String str2 = new String(b,"gbk");
這句話的意思是把字節數組b,用gbk字符集解碼生成新的字符串。實際上是把字節數組b通過gbk到unicode的轉換算法轉換成unicode碼如圖2
手動轉碼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,"utf-8");//類似I/O時,用了與發送方不匹配字符集。導致下面需要手動轉碼 byte[] b2 = str2.getBytes("utf-8");//企圖轉回來 show(b2); System.out.println(new String(str2.getBytes("utf-8"),"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
-17 -65 -67 -17 -65 -67
錕斤拷上面的過程與我們開頭提到的web中手動轉碼的問題非常相像。但是,這次爲什麼失敗了呢。先讓我們看看上面代碼做了什麼。相當於1.首先把str通過gbk編碼得到了字節數組b2.把字節數組b用uft8字符集解碼生成新的字符str23.把str2字符用utf-8字符集編碼成字節數組b2(2)(3)看似可逆。實際上是1.首先把str通過gbk編碼得到了字節數組b2.利用字節數組b,通過utf-8到unicode的轉換算法生成新的字符str23.把字符串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的格式,但是這種算法仍然能按照某種方式解析,所以數據沒出現錯誤,所以你想轉換回來的時候,還能轉換回來(所謂的兼容性好)。所以說,手工轉碼不是萬能的。
字符編碼問題之手動轉碼並不萬能
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.