中文亂碼恢復

  中文亂碼是開發中常見的問題,通常狀況下出現中文亂碼是由於對 中文字符 的編碼方式和解密方式不一致致使的,這種狀況下,只要設置統一的字符編碼方式就能夠解決或者避免出現亂碼問題。但在項目開發中,偶爾會出現無論怎麼設置編碼方式,都不能正確恢復亂碼的問題。上次正好遇到了這樣一箇中文亂碼問題,在解決問題的過程當中,瞭解了字符編碼的歷史,常見編碼字符集的由來,對解決中文亂碼問題起到了很大的幫助(對字符編碼以及各類常見字符集的分析總結,會在後面的博客中發出來)。java

  對於切換編碼方式沒法解決的中文亂碼問題,常見的緣由是:一段使用A編碼方式的中文,在傳輸、存儲的過程當中被錯誤的使用B編碼方式編碼,再次展現的時候使用A編碼方式解碼,最終出現了很奇怪的亂碼問題。數據庫

  例如: 你好  這個中文單詞,最開始使用 UTF-8 編碼,那麼其16進制編碼爲:E4BDA0 E5A5BD,然而在解碼的時候,錯誤的使用了 GB18030 編碼方式,也就是說,這個時候解碼程序以GB18030字符集解碼 E4BD A0E5 A5BD 這段16進制,獲得的結果是:浣犲ソ 。很明顯,這個時候亂碼了。這時,在傳輸、存儲這段亂碼文本的時候,使用了 UTF-8 編碼方式來進行編碼,也就是對  浣犲ソ  這段文本進行編碼,獲得16進制編碼爲:E6B5A3E78AB2E382BD20 ,而後數據庫或文件裏存儲的內容就變成了 E6B5A3E78AB2E382BD20。測試

  對於 E6B5A3E78AB2E382BD20 這段16進制代碼,若是使用 UTF-8 編碼方式來解碼的話,獲得的是:  浣犲ソ  ,亂碼了。而若是使用 GB18030字符集 來解碼的話,獲得的是: 嫺g姴銈??  這樣的亂碼。無論使用其餘的各類編碼字符集進行解碼,獲得的結果都是同樣——各類各樣的亂碼。網站

  從亂碼的過程能夠看出,關鍵的一步在於第一次解碼的時候,也就是使用 GB18030字符集解碼的時候,亂碼了,後面就是按照亂碼文本進行存儲,就算是用存儲時的字符集解碼,獲得的依然是亂碼文本。編碼

  這個時候怎麼辦呢?瞎猜。lua

  嘗試各類常見的字符集,先推測最開始用什麼字符集編碼的,後來又用的什麼字符集解碼的,對各類可能都嘗試一遍,看哪一種組合的結果能推導出正確的中文文本,就能夠知道若是恢復了。spa

 

  本身寫了一個恢復中文亂碼的程序,成功的恢復了亂碼的中文文本,並在後續的亂碼問題修復中屢次使用,貼出來供你們參考一下。code

package com.zy.test.encode;

import java.io.UnsupportedEncodingException;

public class EncodeTest {

    private static String[] charsetArr = {"UTF-8","GB18030","GB2312","GBK","Windows-1252","ISO8859-1"};

    public static void testAllCharset(String text) throws UnsupportedEncodingException {
        if (text == null || text.length() == 0) {
            System.out.println("文本不能爲空");
            return;
        }

        System.out.println("假設當前編碼       假設原始編碼          編碼後的內容");
        printSeparator();

        for (String curCharset : charsetArr) {
            byte[] btArr = text.getBytes(curCharset);
            for (String originCharset : charsetArr) {
                if (originCharset.equals(curCharset)) {
                    continue;
                }
                String encodeText = new String(btArr,originCharset);
                printTable(curCharset, originCharset, encodeText);
            }
            printSeparator();
        }
    }

    private static void printSeparator() {
        System.out.println("--------------------------------------------------------");
    }

    private static void printTable(String curCharset, String originCharset, String encodeText) {
        System.out.print(curCharset);
        for (int i = 0; i < 15 - curCharset.length(); i++) {
            System.out.print(" ");
        }
        System.out.print("|   " + originCharset);
        for (int i = 0; i < 16 - originCharset.length(); i++) {
            System.out.print(" ");
        }
        System.out.println("|     " + encodeText);
    }

    public static void main(String[] args) throws UnsupportedEncodingException {
        //測試亂碼
        testAllCharset("浣犲ソ");
    }
}

  執行結果以下:blog

假設當前編碼       假設原始編碼          編碼後的內容
--------------------------------------------------------
UTF-8          |   GB18030         |     忙碌聥貓爐聲
UTF-8          |   GB2312          |     忙碌�貓爐�
UTF-8          |   GBK             |     忙碌聥貓爐聲
UTF-8          |   Windows-1252    |     测试
UTF-8          |   ISO8859-1       |     测试
--------------------------------------------------------
GB18030        |   UTF-8           |     �0�3�0�8�0�1���0�4�0�1
GB18030        |   GB2312          |     �0�3�0�8�0�1è�0�4�0�1
GB18030        |   GBK             |     �0�3�0�8�0�1è�0�4�0�1
GB18030        |   Windows-1252    |     �0Š3�0…8�0‚1¨¨�0…4�0ƒ1
GB18030        |   ISO8859-1       |     0Š30…80‚1¨¨0…40ƒ1
--------------------------------------------------------
GB2312         |   UTF-8           |     ???��??
GB2312         |   GB18030         |     ???è??
GB2312         |   GBK             |     ???è??
GB2312         |   Windows-1252    |     ???¨¨??
GB2312         |   ISO8859-1       |     ???¨¨??
--------------------------------------------------------
GBK            |   UTF-8           |     ???��??
GBK            |   GB18030         |     ???è??
GBK            |   GB2312          |     ???è??
GBK            |   Windows-1252    |     ???¨¨??
GBK            |   ISO8859-1       |     ???¨¨??
--------------------------------------------------------
Windows-1252   |   UTF-8           |     �?�?
Windows-1252   |   GB18030         |     嫺?璇?
Windows-1252   |   GB2312          |     嫺?璇?
Windows-1252   |   GBK             |     嫺?璇?
Windows-1252   |   ISO8859-1       |     ��
--------------------------------------------------------
ISO8859-1      |   UTF-8           |     測試
ISO8859-1      |   GB18030         |     嫺嬭瘯
ISO8859-1      |   GB2312          |     嫺�璇�
ISO8859-1      |   GBK             |     嫺嬭瘯
ISO8859-1      |   Windows-1252    |     测试
--------------------------------------------------------

  從執行結果能夠看出,只有在  假設當前編碼   爲   ISO9959-1  ,假設原始編碼  爲   UTF-8   時,正確的恢復了亂碼的中文文本。由此能夠得出,該亂碼最開始使用 UTF-8 編碼,以後錯誤的使用了  ISO8859-1  字符集進行解碼,並按照錯誤解碼獲得的二進制進行存儲、傳輸(實際上大多數的中文亂碼場景都是這樣)。開發

  須要注意的是,這個亂碼恢復代碼僅適用於  被錯誤解碼一次  的狀況,若是有屢次被錯誤解碼,那麼恢復起來就須要嘗試更多可能的字符集組合。另外,若是亂碼後的文本中出現  ??  這樣的狀況,則有可能沒法恢復,由於亂碼以前的信息已經丟失了,例如使用UTF-8編碼,而後使用GB18030解碼,由於UTF-8的編碼範圍遠大於GB18030的編碼範圍,因此解碼的時候,一些在GB18030字符集中找不到的編碼就會丟失掉了。

  另外,推薦一個亂碼恢復的網站,http://www.mytju.com/classcode/tools/messycoderecover.asp  能夠對亂碼進行必定的恢復,原理跟我上面說的同樣(實際使用中發現有時亂碼沒法恢復,可是使用上面的程序就能夠)。

 

  正確的恢復了亂碼的中文,找到了最開始的編碼方式和錯誤解碼時的編碼方式,那該如何在程序中解決這個問題呢?

  通常狀況下,在錯誤解碼的地方設置使用正確的編碼字符集就能夠解決問題。因此避免中文亂碼的原則就是使用統一的字符集,全部的地方都統一使用某個字符集。

  若是無法設置字符集,或者設置了正確的字符集但沒有生效而又找不到解決方案的狀況下,能夠手動的對亂碼文本進行轉碼(不推薦這種方式)。

  例如,在上面測試的程序中,最原始的編碼是UTF-8,錯誤解碼使用的是ISO8859-1,那麼能夠用下面的方式進行轉碼恢復:

String newStr = new String(luanma.getBytes("ISO8859-1"),"UTF-8");

  

  以上就是對處理此次中文亂碼問題的一個小總結,但願能對別人有所幫助!

相關文章
相關標籤/搜索