前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >解密乱码的前世今生:为什么你看到的不是你想要的?

解密乱码的前世今生:为什么你看到的不是你想要的?

作者头像
找Bug
发布2025-01-20 20:11:04
发布2025-01-20 20:11:04
11900
代码可运行
举报
文章被收录于专栏:你的Bug我做主你的Bug我做主
运行总次数:0
代码可运行

在数字世界中,乱码是个再熟悉不过的现象了。无论是打开一份文档、接收到一封邮件,还是在终端里执行一条命令,突然冒出的“天书”让人一脸问号。那么,乱码到底是如何产生的?我们又该如何应对?

一、什么是乱码?

简单来说,乱码是指文本编码与解码不匹配导致的不可识别字符现象。想象你用中文的规则(比如 GBK)写了一句话,却用英文的规则(比如 ASCII)来解读它,这就像听不懂外语一样,结果自然是一堆“乱七八糟”的字符。

二、乱码的“生成器”——编码与解码的冲突

乱码的根源在于 编码 和 解码 的不一致。

1.编码是什么?

编码是将人类可读的文本转化为计算机能理解的二进制数据的过程。不同的编码规则(如 ASCII、UTF-8、GBK)对字符的处理方式各有不同。

2.解码是什么?

解码是将二进制数据还原为可读文本的过程。如果解码时采用的规则和编码时不一致,就会出现乱码。

三、常见编码格式与它们的“矛盾”

1.ASCII

最早的字符编码标准之一,只支持 128 个字符,主要用于英语。

问题:对于中文等多语言来说,它根本不够用。

2.GBK/GB2312

针对中文设计的编码,支持大量汉字。

问题:与其他编码(如 UTF-8)容易发生冲突。

3.UTF-8

一个通用的编码标准,兼容 ASCII,支持世界上几乎所有语言。

问题:如果软件默认采用 GBK 解码 UTF-8 编码的数据,就会显示乱码。

4.ISO-8859-1

用于欧洲语言的编码,常见于网页。

问题:遇到中文时无法正确显示。

四、乱码是如何产生的?

1.跨系统传输

你从 Windows 系统保存的文件用 UTF-8 编码,却用 Mac 的 GBK 打开,自然会显示乱码。

浏览器编码设置不当

某些老旧网页没有声明编码方式,浏览器只能“猜”。猜错了,乱码就来了。

3.数据库存储

数据库存储乱码问题一直是开发中常见的“坑”,尤其在多语言支持和系统迁移时更容易出现。这类乱码问题通常发生在数据的插入、存储或读取阶段,具体场景包括:

1) 数据库编码设置不一致

数据库的编码配置主要有以下几个层级,任何一个环节不一致都可能导致乱码:

客户端编码

应用程序(如Java、Python等)通过驱动程序与数据库交互时,需要明确指定编码。如果应用程序用UTF-8,但数据库驱动未正确配置,插入的中文数据可能直接变成乱码。

数据库服务器编码

数据库服务器的默认编码必须与应用程序匹配。例如,MySQL中可以用以下命令查看默认编码:

SHOW VARIABLES LIKE 'character_set%';

结果中的character_set_server代表服务器默认编码,character_set_database是当前数据库的默认编码。

表的字符集

每个表的字符集可能不同。如果表是latin1字符集,而插入UTF-8数据,显示时就会变成乱码。可以用以下命令查看表的字符集:

代码语言:javascript
代码运行次数:0
复制
SHOW CREATE TABLE your_table_name;

字段的字符集

即使表的字符集正确,某个字段单独设置了不同的字符集,也会导致问题。

2) 数据库迁移导致的乱码

当数据库从一种系统迁移到另一种系统时,可能因导出、导入过程中的编码不一致而出现乱码。比如:

使用mysqldump导出数据时,如果未指定编码:

代码语言:javascript
代码运行次数:0
复制
mysqldump -u user -p database > backup.sql

默认情况下会使用数据库的字符集,但导入目标数据库时如果字符集不同,数据可能显示为乱码。

那么我用java简单的演示一下乱码的形成,乱码基本常见的就是四种,我们一一来试一下。

代码语言:javascript
代码运行次数:0
复制
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;

public class Test{

    public static void main(String[]args) throws UnsupportedEncodingException {

        String field="鸡你实在是太美";
        //utf-8存储一下字符
        byte[] Basketball = field.getBytes(StandardCharsets.UTF_8);
        //utf-8读取
        String Chicken=new String(Basketball,StandardCharsets.UTF_8);
        System.out.println(Chicken);
        //gbk读取
        String Sing=new String(Basketball,"GBK");
        System.out.println(Sing);
    }
}

输出:

代码语言:javascript
代码运行次数:0
复制
鸡你实在是太美
楦′綘瀹炲湪鏄お缇�

我们看到如果utf-8编码的,用utf-8就能正常读取,但用gbk编码读取就会变成类似古文似的乱码。

下面展示先用utf-8编码,gbk读取后用gbk存,然后再用utf8读取,这时如果字符是偶数个,最后面会出现问号的乱码,偶数则显示正常,这个例子就是奇数的乱码。

代码语言:javascript
代码运行次数:0
复制
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;

public class Test{

    public static void main(String[]args) throws UnsupportedEncodingException {


        String field="鸡你实在是太美";
        //utf-8存储一下字符
        byte[] Basketball = field.getBytes(StandardCharsets.UTF_8);
        //utf-8读取
        String Chicken=new String(Basketball,StandardCharsets.UTF_8);
        System.out.println(Chicken);
        //gbk读取
        String Sing=new String(Basketball,"GBK");
        System.out.println(Sing);

        //gbk读取后gbk存
        byte[] Dance= Sing.getBytes("GBK");
        //再utf-8读取
        String Rap=new String(Dance,StandardCharsets.UTF_8);
        System.out.println(Rap);

    }
}

输出:

代码语言:javascript
代码运行次数:0
复制
鸡你实在是太美
楦′綘瀹炲湪鏄お缇�
鸡你实在是太�?

下面展示先用gbk编码,然后utf-8读取的乱码

代码语言:javascript
代码运行次数:0
复制
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;

public class Test{

    public static void main(String[]args) throws UnsupportedEncodingException {


        String field="鸡你实在是太美";
        //gbk存储一下字符
        byte[] Basketball = field.getBytes("GBK");
        //utf-8读取
        String Chicken=new String(Basketball,StandardCharsets.UTF_8);
        System.out.println(Chicken);

    }

}

输出:

代码语言:javascript
代码运行次数:0
复制
����ʵ����̫��

下面展示先用gbk编码,然后utf-8读取,存储,再用gbk读取的乱码

代码语言:javascript
代码运行次数:0
复制
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;

public class Test{

    public static void main(String[]args) throws UnsupportedEncodingException {

        String field="鸡你实在是太美";
        //gbk存储一下字符
        byte[] Basketball = field.getBytes("GBK");
        //utf-8读取
        String Chicken=new String(Basketball,StandardCharsets.UTF_8);
        System.out.println(Chicken);
        //utf-8读取后utf-8存
        byte[] Dance= Chicken.getBytes(StandardCharsets.UTF_8);
        //再gbk读取
        String Rap=new String(Dance,"GBK");
        System.out.println(Rap);
    }

}

输出:

代码语言:javascript
代码运行次数:0
复制
����ʵ����̫��
锟斤拷锟斤拷实锟斤拷锟斤拷太锟斤拷

最后附上一般乱码的对照表,希望大家在排查乱码问题的时候会有所帮助。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-01-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 找Bug 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档