<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轉(zhuǎn)UTF-8】


    在很多論壇、網(wǎng)上經(jīng)常有網(wǎng)友問“ 為什么我使用 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轉(zhuǎn)換成UTF-8呢?”

    參考前面的
    【Java基礎(chǔ)專題】編碼與亂碼(03)----String的toCharArray()方法測(cè)試 一文,我們就知道原因了。因?yàn)槿绻蛻舳耸褂肎BK、UTF-8編碼,編碼后的字節(jié)經(jīng)過ISO-8859-1傳輸,再用原來(lái)相同的編碼方式進(jìn)行解碼,這個(gè)過程是“無(wú)損的轉(zhuǎn)換”---- 因?yàn)樵己妥罱K的編碼方式相同。

    但是如果客戶端使用GBK編碼,到了服務(wù)器端要轉(zhuǎn)換成UTF-8,或者相反的過程。想一想,字節(jié)還是那些字節(jié),但是編碼的規(guī)則變了。原來(lái)GBK編碼后的4個(gè)字節(jié)要用UTF-8的每個(gè)字符3個(gè)字節(jié)的規(guī)則編碼,怎么能不亂碼呢?

    所以從現(xiàn)在開始,不要再犯這種錯(cuò)誤了。new String(tmp.getBytes("GBK"), "UTF-8") 這個(gè)過程,JVM內(nèi)部是不會(huì)幫你自動(dòng)對(duì)字節(jié)進(jìn)行擴(kuò)展以適應(yīng)UTF-8的編碼的。正確的方法應(yīng)該是根據(jù)UTF-8的編碼規(guī)則進(jìn)行字節(jié)的擴(kuò)充,即手動(dòng)從2個(gè)字節(jié)變成3個(gè)字節(jié),然后再轉(zhuǎn)換成十六進(jìn)制的UTF-8編碼。

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




    下面給出一個(gè)從網(wǎng)絡(luò)上得到的Java轉(zhuǎn)碼方法,原文鏈接見:
    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編碼下的字符數(shù)組,一個(gè)中文字符對(duì)應(yīng)這里的一個(gè)c[i]
            char c[] = chenese.toCharArray();
            
            
    // Step 2: UTF-8使用3個(gè)字節(jié)存放一個(gè)中文字符,所以長(zhǎng)度必須為字符的3倍
            byte[] fullByte = new byte[3 * c.length];
            
            
    // Step 3: 循環(huán)將字符的GBK編碼轉(zhuǎn)換成UTF-8編碼
            for (int i = 0; i < c.length; i++{
                
                
    // Step 3-1:將字符的ASCII編碼轉(zhuǎn)換成2進(jìn)制值
                int m = (int) c[i];
                String word 
    = Integer.toBinaryString(m);
                System.out.println(word);

                
    // Step 3-2:將2進(jìn)制值補(bǔ)足16位(2個(gè)字節(jié)的長(zhǎng)度) 
                StringBuffer sb = new StringBuffer();
                
    int len = 16 - word.length();
                
    for (int j = 0; j < len; j++{
                    sb.append(
    "0");
                }

                
    // Step 3-3:得到該字符最終的2進(jìn)制GBK編碼
                
    // 形似:1000 0010 0111 1010
                sb.append(word);
                
                
    // Step 3-4:最關(guān)鍵的步驟,根據(jù)UTF-8的漢字編碼規(guī)則,首字節(jié)
                
    // 以1110開頭,次字節(jié)以10開頭,第3字節(jié)以10開頭。在原始的2進(jìn)制
                
    // 字符串中插入標(biāo)志位。最終的長(zhǎng)度從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:將新的字符串進(jìn)行分段截取,截為3個(gè)字節(jié)
                String s1 = sb.substring(08);
                String s2 
    = sb.substring(816);
                String s3 
    = sb.substring(16);

                
    // Step 3-6:最后的步驟,把代表3個(gè)字節(jié)的字符串按2進(jìn)制的方式
                
    // 進(jìn)行轉(zhuǎn)換,變成2進(jìn)制的整數(shù),再轉(zhuǎn)換成16進(jìn)制值
                byte b0 = Integer.valueOf(s1, 2).byteValue();
                
    byte b1 = Integer.valueOf(s2, 2).byteValue();
                
    byte b2 = Integer.valueOf(s3, 2).byteValue();
                
                
    // Step 3-7:把轉(zhuǎn)換后的3個(gè)字節(jié)按順序存放到字節(jié)數(shù)組的對(duì)應(yīng)位置
                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:返回繼續(xù)解析下一個(gè)中文字符
            }

            
    return fullByte;
        }

    }

    最終的測(cè)試結(jié)果是正確的:string from GBK to UTF-8 byte:  中文。

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

    所以要讓這個(gè)方法更加完美,最好的方法就是加入對(duì)字符Unicode區(qū)間的判斷

    UCS-2編碼(16進(jìn)制) UTF-8 字節(jié)流(二進(jìn)制)
    0000 - 007F 0xxxxxxx
    0080 - 07FF 110xxxxx 10xxxxxx
    0800 - FFFF 1110xxxx 10xxxxxx 10xxxxxx






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

    【UTF-8轉(zhuǎn)GBK】

    道理和上面的相同,只是一個(gè)逆轉(zhuǎn)的過程,不多說(shuō)了


    但是最終的建議還是:能夠統(tǒng)一編碼就統(tǒng)一編碼吧!要知道編碼的轉(zhuǎn)換是相當(dāng)?shù)暮臅r(shí)的工作



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


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

    你所說(shuō)的tmp.getBytes("UTF-8");是直接從內(nèi)存中取出Unicode,然后轉(zhuǎn)換成UTF-8編碼的字符,再得到該字符的字節(jié)數(shù)組。這個(gè)時(shí)候的編碼轉(zhuǎn)換流程是:

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

    而我文章中的內(nèi)容是針對(duì)“原始數(shù)據(jù)以GBK格式傳輸,在目的端要轉(zhuǎn)換成UTF-8的格式保存”,從時(shí)機(jī)上說(shuō)比你這個(gè)要早了一步,這個(gè)時(shí)候的編碼轉(zhuǎn)換流程是:

    GBK字符 ---> GBK字節(jié)---> 以ISO-8859-1 單字節(jié)傳輸 ---> 【轉(zhuǎn)換為UTF-8字節(jié)】---> UTF-8字符 ---> Unicode字符

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

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

    GBK和UTF-8都是交換碼,只是字節(jié),所謂的GBK字符是指誤將GBK當(dāng)做ISO-8859-1轉(zhuǎn)換成的字符吧?
    ==================================================
    準(zhǔn)確說(shuō)不是誤傳,而是HTTP協(xié)議只支持使用ISO-8859-1的協(xié)議傳遞,客戶端的瀏覽器是按照GBK的編碼轉(zhuǎn)換成4個(gè)字節(jié)發(fā)出的。字節(jié)的內(nèi)容和順序還是正確的。

    其次你說(shuō)的交換碼是什么意思?請(qǐng)指教


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

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

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

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

    我的印象中,UTF-8是使用3個(gè)字節(jié)來(lái)表示中文的,GB18030是使用2個(gè)字節(jié),他們對(duì)同一個(gè)漢字的編碼各自不同,你說(shuō)的兼容是指那方面的呢?

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

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

    這樣targetBytes就直接保存的就是目標(biāo)charset的byte流。  回復(fù)  更多評(píng)論
      
    <2010年3月>
    28123456
    78910111213
    14151617181920
    21222324252627
    28293031123
    45678910

    常用鏈接

    留言簿(21)

    隨筆分類

    隨筆檔案

    BlogJava熱點(diǎn)博客

    好友博客

    搜索

    •  

    最新評(píng)論

    閱讀排行榜

    評(píng)論排行榜

    主站蜘蛛池模板: 欧美男同gv免费网站观看 | 看亚洲a级一级毛片| 国产精品亚洲а∨天堂2021| 野花视频在线官网免费1| 亚洲精品偷拍视频免费观看| 视频免费在线观看| 色播精品免费小视频| 女人被男人躁的女爽免费视频| 免费在线不卡视频| 亚洲AV无码日韩AV无码导航 | 亚洲VA中文字幕无码一二三区 | 亚洲一区AV无码少妇电影| 福利片免费一区二区三区| 韩日电影在线播放免费版| 久久免费看黄a级毛片| 日本高清色本免费现在观看| 亚洲精品NV久久久久久久久久| 久久久久亚洲精品影视| 亚洲日韩国产精品乱-久| 一级毛片免费视频网站| 99久久久国产精品免费蜜臀| 午夜一级毛片免费视频| 日韩亚洲欧洲在线com91tv| 亚洲偷自精品三十六区| 国产精品免费观看视频| 国产免费不卡v片在线观看| 亚洲国产精品视频| 精品亚洲成a人片在线观看少妇| 亚洲精品日韩一区二区小说| 中国一级特黄高清免费的大片中国一级黄色片 | 日本亚洲免费无线码| 夜色阁亚洲一区二区三区| 91亚洲va在线天线va天堂va国产| 亚洲aⅴ无码专区在线观看| 久久成人免费电影| 国产成人免费ā片在线观看| 亚洲人成网www| 一区二区三区精品高清视频免费在线播放 | 毛片免费在线观看网址| 综合久久久久久中文字幕亚洲国产国产综合一区首| 亚洲视频中文字幕|