在计算机系统或软件中,中文乱码是指由于字符编码不一致或处理不当,导致中文字符无法正常显示,出现乱码现象。这种现象通常表现为中文字符被替换成其他不相关的字符、符号或乱码。本文将探讨中文乱码的成因、常见的字符编码方式,以及如何快速解决乱码问题。

1 什么是中文乱码?

中文乱码是指在计算机系统或软件中,由于字符编码不一致或处理不当,导致中文字符无法正常显示,出现乱码现象。这种现象通常表现为中文字符被替换成其他不相关的字符、符号或乱码。

2 什么是字符编码?

字符编码(Character Encoding)是一种规则或约定,它将字符(如字母、数字、标点符号等)映射到计算机中的二进制数据。简单来说,字符编码就是将人类可读的字符转换为计算机可以处理的二进制数据的过程。

计算机只认 0 和 1,所有的信息最终都是一个二进制数。一个字节由 8 个二进制数组成,可以表示 256 种状态(2^8),从 00000000 到 11111111。为了让计算机能够识别和处理各种字符,需要使用字符编码来对字符进行编码和解码。常见的字符编码包括 ASCII、UTF-8、UTF-16、GBK、GB2312 等。

3 常见的字符编码方式

ASCII

ASCII 码由电报码发展而来,第一版标准发布于 1963 年,最后一次更新则是在 1986 年,至今为止共定义了 128 个字符。其中 33 个字符无法显示在一般的设备上,需要用特殊的设备才能显示。

ASCII 码的局限在于只能显示 26 个基本拉丁字母、阿拉伯数字和英式标点符号,因此只能用于显示现代美国英语,对于其他一些语言则无能为力。

Unicode

Unicode 是一种统一的字符编码标准,旨在涵盖世界上所有的字符。Unicode 至今仍在不断增修,每个新版本都会加入更多新的字符。目前最新的版本为 2020 年 3 月公布的 13.0,收录了 13 万个字符。

Unicode 是一个很大的集合,现在的规模可以容纳 100 多万个符号。每个符号的编码都不一样,比如,U+0639 表示阿拉伯字母 Ain,U+0041 表示英语的大写字母 A,U+4E25 表示汉字严。

UTF-8

UTF-8 是 Unicode 的一种编码方式,最常见的就是 UTF-8 和 UTF-16。在 UTF-8 中,0-127 号的字符用 1 个字节来表示,使用和 ASCII 相同的编码。只有 128 号及以上的字符才用 2 个、3 个或者 4 个字节来表示。

UTF-8 是一种可变长度的编码方式,优势在于它包罗万象,劣势在于浪费空间。例如,UTF-8 采用了 3 个字节来编码常用的汉字,但常用的汉字没有这么多,这对于计算机来说,就是一种严重的资源浪费。

GB2312

中国国家标准总局于 1980 年发布了 GB2312 编码,即中华人民共和国国家标准简体中文字符集。GB2312 标准共收录 6763 个汉字(2 个字节就够用了),其中一级汉字 3755 个,二级汉字 3008 个;同时收录了包括拉丁字母、希腊字母、日文平假名及片假名字母、俄语西里尔字母在内的 682 个字符。

GB2312 的出现,基本满足了汉字的计算机处理需求。对于人名、古汉语等方面出现的罕用字和繁体字,GB2312 不能处理,就有了 GBK(K 为“扩展”的汉语拼音(kuòzhǎn)第一个声母)。

4 中文乱码是如何出现的?

中文乱码通常是由于编码和解码过程中使用了不同的字符编码方式导致的。例如,使用 GBK 编码将中文字符串 “沉默王二” 转换为字节数组,然后使用 UTF-8 编码将字节数组转回字符串,这将导致字符串在解码时出现乱码。

public class EncodingDemo {

public static void main(String[] args) {

String originalStr = "沉默王二";

String encodedStr = "";

try {

byte[] bytes = originalStr.getBytes("GBK");

encodedStr = new String(bytes, "UTF-8");

} catch (UnsupportedEncodingException e) {

e.printStackTrace();

}

System.out.println("转码前: " + originalStr);

System.out.println("转码后: " + encodedStr);

}

}

程序输出:

转码前: 沉默王二

转码后: ��Ĭ����

在 Unicode 中,� 是一个特殊的符号,它用来表示无法显示,它的十六进制是 0xEF 0xBF 0xBD。那么两个 �� 就是 0xEF 0xBF 0xBD 0xEF 0xBF 0xBD,如果用 GBK 进行解码的话,就是大名鼎鼎的“锟斤拷”。

可以通过代码来验证一下:

// 输出 efbfbdefbfbd

char[] kuijinkao = HexUtil.encodeHex("��", StandardCharsets.UTF_8);

System.out.println(kuijinkao);

// 借助 hutool 转成二进制

byte[] testBytes = HexUtil.decodeHex(kuijinkao);

// 使用 GBK 解码

String testResult = new String(testBytes, Charset.forName("GBK"));

// 输出锟斤拷

System.out.println(testResult);

来看一下输出结果:

efbfbdefbfbd

锟斤拷

5 如何解决中文乱码?

解决中文乱码问题需要确保在编码和解码过程中使用相同的字符编码。以下是一些避免乱码的实践:

使用统一的字符编码:如 UTF-8。它包含了所有 Unicode 字符,并且广泛支持。确保在所有平台和系统上使用相同的编码。

明确指定字符编码:在处理文本文件时,始终明确指定字符编码。例如,在 Java 中使用 InputStreamReader、OutputStreamWriter 时,指定编码参数。

在文档中指定字符编码:在 HTML、XML 等文档中,指定字符编码。例如,在 HTML 页面中添加

确保数据库使用正确的字符集:在创建数据库和表时,明确指定字符集,如 utf8mb4。

与第三方服务通信时确保字符编码一致:在处理 API 请求和响应时,检查字符编码是否匹配。

6 生产环境事故的快速定位与解决

收集信息:了解问题的具体表现,例如哪些页面或功能受到影响,问题的严重程度,以及用户反馈。这将有助于快速定位问题范围。

检查日志:查看服务器日志和应用程序日志,检查是否存在异常信息或错误。日志信息有助于识别问题发生的时间和具体原因。

复现问题:在测试环境中尝试复现问题,以便更深入地了解问题细节。如果无法复现问题,可能需要进一步收集生产环境的详细信息。

定位问题:根据收集到的信息,确定问题可能发生的代码或系统部分。检查相关代码,特别是涉及字符编码、数据传输、数据库操作的部分。

解决问题:修复问题代码,确保字符编码在整个系统中保持一致。进行单元测试和集成测试,验证问题是否已解决。

部署修复:将修复后的代码部署到生产环境。为了避免影响正常服务,可以考虑先在一个小规模的生产环境中进行验证,然后逐步扩大部署范围。

监控:在修复后持续关注系统运行状况,确保问题已得到解决。收集用户反馈,确认用户满意度。

总结经验:针对此次问题,总结经验教训,分析问题产生的根本原因,优化开发和测试流程,避免类似问题再次发生。

通过以上步骤,可以快速定位并解决中文乱码问题,确保系统的稳定性和用户体验。

7 思维导图

8 参考链接

解决中文乱码:字符编码全攻略 - ASCII、Unicode、UTF-8、GB2312详解