日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

编码与乱码(05)---GBK与UTF-8之间的转换--转载

發布時間:2025/4/5 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 编码与乱码(05)---GBK与UTF-8之间的转换--转载 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

原文地址:http://www.blogjava.net/pengpenglin/archive/2010/02/22/313669.html

【GBK轉UTF-8】


在很多論壇、網上經常有網友問“?為什么我使用 new String(tmp.getBytes("ISO-8859-1"), "UTF-8") 或者 new String(tmp.getBytes("ISO-8859-1"), "GBK")可以得到正確的中文,但是使用 new String(tmp.getBytes("GBK"), "UTF-8") 卻不能將GBK轉換成UTF-8呢?”

參考前面的【Java基礎專題】編碼與亂碼(03)----String的toCharArray()方法測試?一文,我們就知道原因了。因為如果客戶端使用GBK、UTF-8編碼,編碼后的字節經過ISO-8859-1傳輸,再用原來相同的編碼方式進行解碼,這個過程是“無損的轉換”---- 因為原始和最終的編碼方式相同。

但是如果客戶端使用GBK編碼,到了服務器端要轉換成UTF-8,或者相反的過程。想一想,字節還是那些字節,但是編碼的規則變了。原來GBK編碼后的4個字節要用UTF-8的每個字符3個字節的規則編碼,怎么能不亂碼呢?

所以從現在開始,不要再犯這種錯誤了。new String(tmp.getBytes("GBK"), "UTF-8") 這個過程,JVM內部是不會幫你自動對字節進行擴展以適應UTF-8的編碼的。正確的方法應該是根據UTF-8的編碼規則進行字節的擴充,即手動從2個字節變成3個字節,然后再轉換成十六進制的UTF-8編碼。

在這個專題的第一篇文章【Java基礎專題】編碼與亂碼(01)---編碼基礎?開頭,我們就已經介紹了這個規則:
?①得到每個字符的2進制GBK編碼
?②將該16進制的GBK編碼轉換成2進制的字符串(2個字節)
?③分別在字符串的首位插入110,在第9位插入10,在第17位插入10三個字符串,得到3個字節
?④將這3個字節分別轉換成16進制編碼,得到最終的UTF-8編碼。




下面給出一個從網絡上得到的Java轉碼方法,原文鏈接見:http://jspengxue.javaeye.com/blog/40781。下面的代碼做了小小的修改

?

package?example.encoding;

/**
?*?The?Class?CharacterEncodeConverter.
?*/
public?class?CharacterEncodeConverter?{

????/**
?????*?The?main?method.
?????*?
?????*?@param?args?the?arguments
?????*/
????public?static?void?main(String[]?args)?{

????????try?{
????????????CharacterEncodeConverter?convert?=?new?CharacterEncodeConverter();
????????????byte[]?fullByte?=?convert.gbk2utf8("中文");
????????????String?fullStr?=?new?String(fullByte,?"UTF-8");
????????????System.out.println("string?from?GBK?to?UTF-8?byte:??"?+?fullStr);

????????}?catch?(Exception?e)?{
????????????e.printStackTrace();
????????}
????}

????/**
?????*?Gbk2utf8.
?????*?
?????*?@param?chenese?the?chenese
?????*?
?????*?@return?the?byte[]
?????*/
????public?byte[]?gbk2utf8(String?chenese)?{
????????
????????//?Step?1:?得到GBK編碼下的字符數組,一個中文字符對應這里的一個c[i]
????????char?c[]?=?chenese.toCharArray();
????????
????????//?Step?2:?UTF-8使用3個字節存放一個中文字符,所以長度必須為字符的3倍
????????byte[]?fullByte?=?new?byte[3?*?c.length];
????????
????????//?Step?3:?循環將字符的GBK編碼轉換成UTF-8編碼
????????for?(int?i?=?0;?i?<?c.length;?i++)?{
????????????
????????????//?Step?3-1:將字符的ASCII編碼轉換成2進制值
????????????int?m?=?(int)?c[i];
????????????String?word?=?Integer.toBinaryString(m);
????????????System.out.println(word);

????????????//?Step?3-2:將2進制值補足16位(2個字節的長度)?
????????????StringBuffer?sb?=?new?StringBuffer();
????????????int?len?=?16?-?word.length();
????????????for?(int?j?=?0;?j?<?len;?j++)?{
????????????????sb.append("0");
????????????}
????????????//?Step?3-3:得到該字符最終的2進制GBK編碼
????????????//?形似:1000?0010?0111?1010
????????????sb.append(word);
????????????
????????????//?Step?3-4:最關鍵的步驟,根據UTF-8的漢字編碼規則,首字節
????????????//?以1110開頭,次字節以10開頭,第3字節以10開頭。在原始的2進制
????????????//?字符串中插入標志位。最終的長度從16--->16+3+2+2=24。
????????????sb.insert(0,?"1110");
????????????sb.insert(8,?"10");
????????????sb.insert(16,?"10");
????????????System.out.println(sb.toString());

????????????//?Step?3-5:將新的字符串進行分段截取,截為3個字節
????????????String?s1?=?sb.substring(0,?8);
????????????String?s2?=?sb.substring(8,?16);
????????????String?s3?=?sb.substring(16);

????????????//?Step?3-6:最后的步驟,把代表3個字節的字符串按2進制的方式
????????????//?進行轉換,變成2進制的整數,再轉換成16進制值
????????????byte?b0?=?Integer.valueOf(s1,?2).byteValue();
????????????byte?b1?=?Integer.valueOf(s2,?2).byteValue();
????????????byte?b2?=?Integer.valueOf(s3,?2).byteValue();
????????????
????????????//?Step?3-7:把轉換后的3個字節按順序存放到字節數組的對應位置
????????????byte[]?bf?=?new?byte[3];
????????????bf[0]?=?b0;
????????????bf[1]?=?b1;
????????????bf[2]?=?b2;
????????????
????????????fullByte[i?*?3]?=?bf[0];????????????
????????????fullByte[i?*?3?+?1]?=?bf[1];????????????
????????????fullByte[i?*?3?+?2]?=?bf[2];
????????????
????????????//?Step?3-8:返回繼續解析下一個中文字符
????????}
????????return?fullByte;
????}
}


最終的測試結果是正確的:string from GBK to UTF-8 byte:? 中文。

但是這個方法并不是完美的!要知道這個規則只對中文起作用,如果傳入的字符串中包含有單字節字符,如a+3中文,那么解析的結果就變成:string from GBK to UTF-8 byte:? ?????????中文了。為什么呢?道理很簡單,這個方法對原本在UTF-8中應該用單字節表示的數字、英文字符、符號都變成3個字節了,所以這里有9個?,代表被轉換后的a、+、3字符。

所以要讓這個方法更加完美,最好的方法就是加入對字符Unicode區間的判斷

UCS-2編碼(16進制)UTF-8 字節流(二進制)
0000 - 007F0xxxxxxx
0080 - 07FF110xxxxx 10xxxxxx
0800 - FFFF1110xxxx 10xxxxxx 10xxxxxx







漢字的Unicode編碼范圍為\u4E00-\u9FA5 \uF900-\uFA2D,如果不在這個范圍內就不是漢字了。

【UTF-8轉GBK】

道理和上面的相同,只是一個逆轉的過程,不多說了

但是最終的建議還是:能夠統一編碼就統一編碼吧!要知道編碼的轉換是相當的耗時的工作

轉載于:https://www.cnblogs.com/davidwang456/p/4841202.html

總結

以上是生活随笔為你收集整理的编码与乱码(05)---GBK与UTF-8之间的转换--转载的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。