中文乱码恢复

  中文乱码是开发中常见的问题,通常状况下出现中文乱码是由于对 中文字符 的编码方式和解密方式不一致致使的,这种状况下,只要设置统一的字符编码方式就能够解决或者避免出现乱码问题。但在项目开发中,偶尔会出现无论怎么设置编码方式,都不能正确恢复乱码的问题。上次正好遇到了这样一个中文乱码问题,在解决问题的过程当中,了解了字符编码的历史,常见编码字符集的由来,对解决中文乱码问题起到了很大的帮助(对字符编码以及各类常见字符集的分析总结,会在后面的博客中发出来)。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");

  

  以上就是对处理此次中文乱码问题的一个小总结,但愿能对别人有所帮助!

相关文章
相关标签/搜索