<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    posts - 262,  comments - 221,  trackbacks - 0

    【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(08);
                String s2 
    = sb.substring(816);
                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 - 007F 0xxxxxxx
    0080 - 07FF 110xxxxx 10xxxxxx
    0800 - FFFF 1110xxxx 10xxxxxx 10xxxxxx






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

    【UTF-8轉GBK】

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


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



    -------------------------------------------------------------
    生活就像打牌,不是要抓一手好牌,而是要盡力打好一手爛牌。
    posted on 2010-02-22 23:00 Paul Lin 閱讀(37030) 評論(11)  編輯  收藏 所屬分類: J2SE


    FeedBack:
    # re: 【Java基礎專題】編碼與亂碼(05)---GBK與UTF-8之間的轉換
    2010-02-24 05:25 | tbw
    學習了。  回復  更多評論
      
    # re: 【Java基礎專題】編碼與亂碼(05)---GBK與UTF-8之間的轉換
    2010-02-24 11:07 | 沒有腦和不高興
    tmp.getBytes("UTF-8")不就得了?  回復  更多評論
      
    # re: 【Java基礎專題】編碼與亂碼(05)---GBK與UTF-8之間的轉換
    2010-02-24 14:38 | Paul Lin
    @沒有腦和不高興

    你所說的tmp.getBytes("UTF-8");是直接從內存中取出Unicode,然后轉換成UTF-8編碼的字符,再得到該字符的字節數組。這個時候的編碼轉換流程是:

    Unicode字符 ---> encode字符 ---> encode byte[]

    而我文章中的內容是針對“原始數據以GBK格式傳輸,在目的端要轉換成UTF-8的格式保存”,從時機上說比你這個要早了一步,這個時候的編碼轉換流程是:

    GBK字符 ---> GBK字節---> 以ISO-8859-1 單字節傳輸 ---> 【轉換為UTF-8字節】---> UTF-8字符 ---> Unicode字符

    帶方括號的就是我文章中講的內容,請注意中間并沒有生成GBK字符。而是直接在字節級就進行轉換了。如果先解碼成GBK字符,再用UTF-8編碼,那就是你說的這種情況了。但是這樣就太繁瑣而且浪費內存空間了  回復  更多評論
      
    # re: 【Java基礎專題】編碼與亂碼(05)---GBK與UTF-8之間的轉換
    2010-02-25 22:12 | bat
    有的網站上說 UTF-8不能包括所有漢字 提倡用GBK 這個影響大嗎?  回復  更多評論
      
    # re: 【Java基礎專題】編碼與亂碼(05)---GBK與UTF-8之間的轉換
    2010-03-01 15:29 | 沒頭腦和不高興
    GBK字符 ---> GBK字節---> 以ISO-8859-1 單字節傳輸 ---> 【轉換為UTF-8字節】---> UTF-8字符 ---> Unicode字符

    GBK和UTF-8都是交換碼,只是字節,所謂的GBK字符是指誤將GBK當做ISO-8859-1轉換成的字符吧?
    那么還是new String(tmp.getBytes("ISO-8859-1"), "GBK").getBytes("UTF-8")  回復  更多評論
      
    # re: 【Java基礎專題】編碼與亂碼(05)---GBK與UTF-8之間的轉換
    2010-03-01 15:31 | 沒頭腦和不高興
    @bat
    UTF-8字匯和GB18030是兼容的,GB18030基本上是GBK的超集,僅規范了個別碼位。所以belabela
      回復  更多評論
      
    # re: 【Java基礎專題】編碼與亂碼(05)---GBK與UTF-8之間的轉換[未登錄]
    2010-03-02 09:35 | Paul Lin
    @沒頭腦和不高興

    GBK和UTF-8都是交換碼,只是字節,所謂的GBK字符是指誤將GBK當做ISO-8859-1轉換成的字符吧?
    ==================================================
    準確說不是誤傳,而是HTTP協議只支持使用ISO-8859-1的協議傳遞,客戶端的瀏覽器是按照GBK的編碼轉換成4個字節發出的。字節的內容和順序還是正確的。

    其次你說的交換碼是什么意思?請指教


    那么還是new String(tmp.getBytes("ISO-8859-1"), "GBK").getBytes("UTF-8")
    ==================================================
    你這個做法沒錯,最終得到的就是從Unicode--->UTF-8編碼,再用這個就可以構造出UTF-8的字符串了。

    但是我個人比較懶(^_^),其次我想節省內存空間(不生成臨時的GBK字符),所以就直接從字節開始轉了

      回復  更多評論
      
    # re: 【Java基礎專題】編碼與亂碼(05)---GBK與UTF-8之間的轉換[未登錄]
    2010-03-02 09:38 | Paul Lin
    @沒頭腦和不高興

    @bat
    UTF-8字匯和GB18030是兼容的,GB18030基本上是GBK的超集,僅規范了個別碼位。所以belabela
    ====================================================

    我的印象中,UTF-8是使用3個字節來表示中文的,GB18030是使用2個字節,他們對同一個漢字的編碼各自不同,你說的兼容是指那方面的呢?

    GB18030 》GB2312 》GBK 這個我就記得是兼容的  回復  更多評論
      
    # re: 【Java基礎專題】編碼與亂碼(05)---GBK與UTF-8之間的轉換
    2013-10-28 17:05 | 楊建群
    誰告訴你們utf8的漢字編碼就一定是3個字符啊??  回復  更多評論
      
    # re: 【Java基礎專題】編碼與亂碼(05)---GBK與UTF-8之間的轉換
    2014-01-07 17:31 | blues
    @楊建群
    是的,也有很多兩個的, 只是一部分超出的集合才用3個字節進行擴充的  回復  更多評論
      
    # re: 【Java基礎專題】編碼與亂碼(05)---GBK與UTF-8之間的轉換
    2014-06-18 18:09 | karl
    正常情況下,從外部來的數據都是二進制流。不是以String形式存在。最直觀的就是:從文件流讀取byte[]到java,然后進行編碼轉化。

    byte[] bytes = {FileInputStream從文件讀取二進制bytes};
    byte[] targetBytes = new String(bytes, sourceCharset).getBytes(targetCharset)

    這樣targetBytes就直接保存的就是目標charset的byte流。  回復  更多評論
      
    <2014年6月>
    25262728293031
    1234567
    891011121314
    15161718192021
    22232425262728
    293012345

    常用鏈接

    留言簿(21)

    隨筆分類

    隨筆檔案

    BlogJava熱點博客

    好友博客

    搜索

    •  

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 免费一级毛片在线观看| 久久亚洲AV成人无码国产| 中国黄色免费网站| 亚洲熟妇无码久久精品| 日本视频免费在线| 久久成人免费播放网站| 亚洲七久久之综合七久久| 亚洲毛片αv无线播放一区| 国产1024精品视频专区免费| 一级一片免费视频播放| 亚洲卡一卡2卡三卡4麻豆| 亚洲最大的成网4438| 天天操夜夜操免费视频| 国产拍拍拍无码视频免费| 亚洲精品av无码喷奶水糖心| 好爽…又高潮了毛片免费看| 中文在线观看国语高清免费| 亚洲视频在线观看2018| 91青青青国产在观免费影视| MM1313亚洲精品无码久久| 精品日韩亚洲AV无码| 国产成人亚洲综合无码| 最新中文字幕电影免费观看| 好紧我太爽了视频免费国产| 亚洲AV日韩AV一区二区三曲| 亚洲高清不卡视频| 国产精品亚洲片在线观看不卡| 日本一道在线日本一道高清不卡免费| 免费在线中文日本| 一级做a爱过程免费视频高清| 亚洲熟妇无码AV| 亚洲国产精品美女| 亚洲成人午夜在线| 久久伊人亚洲AV无码网站| 日本一道一区二区免费看 | 亚洲高清视频在线| 久久综合亚洲色一区二区三区| 亚洲午夜福利717| 亚洲国产人成精品| 免费精品国产自产拍观看| 成年美女黄网站色大免费视频|