熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Java編程 >> Java核心技術 >> 正文

Java中的中文編碼問題

2013-11-23 18:58:37  來源: Java核心技術 

  (為什麼要編碼
   
    由於人類的語言有太多因而表示這些語言的符號太多無法用計算機中一個基本的存儲單元byte 來表示因而必須要經過拆分或一些翻譯工作才能讓計算機能理解
   
    所以總的來說編碼的原因可以總結為
   
    計算機中存儲信息的最小單元是一個字節即 個 bit所以能表示的字符范圍是 ~
   
    人類要表示的符號太多無法用一個字節來完全表示
   
    要解決這個矛盾必須需要一個新的數據結構 char從 char 到 byte 必須編碼
   
    (編碼方式
   
    ASCII 碼
   
    ASCII 碼總共有 用一個字節的低 位表示~ 是控制字符如換行回車刪除等~ 是打印字符可以通過鍵盤輸入並且能夠顯示出來
   
    ISO
   
    個字符顯然是不夠用的於是 ISO 組織在 ASCII 碼基礎上又制定了一些列標准用來擴展 ASCII 編碼它們是 ISO~ISO其中 ISO 涵蓋了大多數西歐語言字符所有應用的最廣泛ISO 仍然是單字節編碼它總共能表示 個字符
   
    GB
   
    它的全稱是《信息交換用漢字編碼字符集 基本集》它是雙字節編碼總的編碼范圍是 AF其中從 AA 是符號區總共包含 個符號從 BF 是漢字區包含 個漢字
   
    GBK
   
    全稱叫《漢字內碼擴展規范》是國家技術監督局為 windows 所制定的新的漢字內碼規范它的出現是為了擴展 GB加入更多的漢字它的編碼范圍是 ~FEFE(去掉 XXF)總共有 個碼位它能表示 個漢字它的編碼是和 GB 兼容的也就是說用 GB 編碼的漢字可以用 GBK 來解碼並且不會有亂碼
   
    UTF
   
    說到 UTF 必須要提到 Unicode(Universal Code 統一碼)ISO 試圖想創建一個全新的超語言字典世界上所有的語言都可以通過這本字典來相互翻譯
   
    UTF 具體定義了 Unicode 字符在計算機中存取方法UTF 用兩個字節來表示 Unicode 轉化格式這個是定長的表示方法不論什麼字符都可以用兩個字節表示兩個字節是 個 bit
   
    所以叫 UTFUTF 表示字符非常方便每兩個字節表示一個字符這個在字符串操作時就大大簡化了操作這也是 Java 以 UTF 作為內存的字符存儲格式的一個很重要的原因
   
    UTF
   
    UTF 統一采用兩個字節表示一個字符雖然在表示上非常簡單方便但是也有其缺點有很大一部分字符用一個字節就可以表示的現在要兩個字節表示存儲空間放大了一倍
   
    在現在的網絡帶寬還非常有限的今天這樣會增大網絡傳輸的流量而且也沒必要而 UTF 采用了一種變長技術每個編碼區域有不同的字碼長度不同類型的字符可以是由 ~ 個字節組成
   
    UTF 有以下編碼規則
   
    如果一個字節最高位(第 位)為 表示這是一個 ASCII 字符( F)可見所有 ASCII 編碼已經是 UTF
   
    如果一個字節 開頭連續的 的個數暗示這個字符的字節數例如xxxxx 代表它是雙字節 UTF 字符的首字節
   
    如果一個字節 開始表示它不是首字節需要向前查找才能得到當前字符的首字節



[java] view plaincopy


    /** 
     * byte Array toHex 
     * @param b 
     * @return 
     */  
    public static String toHex(byte[] b) {  
        String result = ;  
        for (int i = ; i < blength; i++) {  
            String hex = IntegertoHexString(b[i] & xFF);  
            if (hexlength() == ) {//高四位置為  
                hex =  + hex;  
            }  
            result = result +   +hextoUpperCase();  
        }  
        return result;  
    }  
      
    /** 
     * char to byte array 
     * @param c 
     * @return 
     */  
    public static byte[] charToByte(char c) {  
           byte[] b = new byte[];  
           b[] = (byte) ((c & xFF) >> );  
           b[] = (byte) (c & xFF);  
           return b;  
       }  
      
    /** 
     * char array toHex 
     * @param c 
     */  
    public static void charToHex(char[] c){  
        for(char cc:c){  
            byte[] b =charToByte(cc);  
            Systemoutprint(toHex(b));  
        }  
    }  
      
    public static void main(String[] args) {  
        String name = I am 君山;  
        charToHex(nametoCharArray());  
        Systemoutprintln();  
        try {  
            byte[] iso = namegetBytes(ISO);  
            Systemoutprintln(toHex(iso));  
            byte[] gb = namegetBytes(GB);  
            Systemoutprintln(toHex(gb));  
            byte[] gbk = namegetBytes(GBK);  
            Systemoutprintln(toHex(gbk));  
            byte[] utf = namegetBytes(UTF);  
            Systemoutprintln(toHex(utf));  
            byte[] utf = namegetBytes(UTF);  
            Systemoutprintln(toHex(utf));  
        } catch (UnsupportedEncodingException e) {  
            eprintStackTrace();  
        }  
    }  

    輸出結果
   
    D B C
   
    D F F
   
    D BE FD C BD
   
    D BE FD C BD
   
    FE FF D B C
   
    D E B E B B


    
    字符串I am 君山用 ISO 編碼下面是編碼結果

  Figure xxx. Requires a heading



   個 char 字符經過 ISO 編碼轉變成 個 byte 數組中文君山被轉化成值是 f 的 bytef 也就是?字符所以經常會出現中文變成?很可能就是錯誤的使用了 ISO 這個編碼導致的
   
    字符串I am 君山用 GB 編碼下面是編碼結果



Figure xxx. Requires a heading

  GB編碼GB 字符集有一個 char 到 byte 的碼表不同的字符編碼就是查這個碼表找到與每個字符的對應的字節然後拼裝成 byte 數組如果查到的碼位值大於 oxff 則是雙字節否則是單字節雙字節高 位作為第一個字節 位作為第二個字節
   
    從結果可以看出前 個字符經過編碼後仍然是 個字節而漢字被編碼成雙字節在第一節中介紹到 GB 只支持 個漢字所以並不是所有漢字都能夠用 GB 編碼
   
    字符串I am 君山用 GBK 編碼下面是編碼結果



Figure xxx. Requires a heading

  你可能已經發現上圖與 GB 編碼的結果是一樣的沒錯 GBK 與 GB 編碼結果是一樣的由此可以得出 GBK 編碼是兼容 GB 編碼的它們的編碼算法也是一樣的不同的是它們的碼表長度不一樣GBK 包含的漢字字符更多所以只要是經過 GB 編碼的漢字都可以用 GBK 進行解碼反過來則不然
   
    字符串I am 君山用 UTF 編碼下面是編碼結果

Figure xxx. Requires a heading

  用 UTF 編碼將 char 數組放大了一倍單字節范圍內的字符在高位補 變成兩個字節中文字符也變成兩個字節從 UTF 編碼規則來看僅僅將字符的高位和地位進行拆分變成兩個字節特點是編碼效率非常高規則很簡單
   
    字符串I am 君山用 UTF 編碼下面是編碼結果

Figure xxx. Requires a heading

  UTF 雖然編碼效率很高但是對單字節范圍內字符也放大了一倍這無形也浪費了存儲空間另外 UTF 采用順序編碼不能對單個字符的編碼值進行校驗如果中間的一個字符碼值損壞後面的所有碼值都將受影響而 UTF 這些問題都不存在UTF 對單字節范圍內字符仍然用一個字節表示對漢字采用三個字節表示
   
    常見問題分析
   
    中文變成了看不懂的字符例如字符串淘!我喜歡!變成了ì ? £ ?? ò ??? £ ?
   
    字符串在解碼時所用的字符集與編碼字符集不一致導致漢字變成了看不懂的亂碼而且是一個漢字字符變成兩個亂碼字符
   
    一個漢字變成一個問號 例如字符串淘!我喜歡!變成了??????
   
    將中文和中文符號經過不支持中文的 ISO 編碼後所有字符變成了?這是因為用 ISO 進行編解碼時遇到不在碼值范圍內的字符時統一用 f 表示這也就是通常所說的黑洞所有 ISO 不認識的字符都變成了?


From:http://tw.wingwit.com/Article/program/Java/hx/201311/26063.html
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.