搜索
首页常见问题中文乱码的产生原因是什么

中文乱码的产生原因是什么

Nov 09, 2022 am 11:14 AM
乱码中文乱码

中文乱码的产生原因:解码方式和编码方式不一致。一个中文字符以utf-8编码会转成3个byte,如果以gbk编码会转成2个byte;而一个英文字符以utf-8编码会转成1个byte,如果以gbk编码会转成1个byte。

中文乱码的产生原因是什么

本教程操作环境:windows7系统、Dell G3电脑。

先说一下什么叫乱码

不知道有没有人这样认为过,一个字符串不仅仅包含字符,还有隐藏着它的编码信息。比如java中String str = "你好";我之前是这样认为的,str这个字符串隐藏着它的编码方式unicode编码或者gbk、iso-8859-1等。这种理解是错误的,字符就是字符没有任何其他信息,正确的理解应该是,人在一个文件中所看到的字符串是系统经过把内存中的数码信息读取也再解码成一些字符最后显示,就是当你双击打开一个文本文件时系统会把内存的数码信息读取显示出来,当你保存一个文本文件时系统会把这个文件以你所设置的编码方式编码,再放进内存中。

所以说乱码也是一些字符,只是奇怪的字符而已,并没有什么”码“。

接着说乱码产生的原因

我们经常看到网上这样解释乱码原因:乱码是因为解码方式和编码方式不一致导致的,这句话本身没有错,但同样这句话的本身就是把乱码概括了而已,它并不能帮助你理解乱码。

所以我们要提的问题是:为什么解码方式和编码方式不一致会出现乱码。

这里以utf-8,gbk,iso-8859-1三种编码方式为例。

     @Test
     public void testEncode() throws Exception {
        String str = "你好",en = "h?h";
        
        System.out.println("========中文字符utf-8=======");
        byte[] utf8 = str.getBytes(); // 以utf-8方式编码 ,default:utf-8
        for (byte b : utf8) {            
            System.out.print(b + "\t");
        }
        
        System.out.println("\n"+"========英文字符utf-8=======");
        byte[] utf8_en = en.getBytes(); // 以utf-8方式编码 ,default:utf-8
        for (byte b : utf8_en) {            
            System.out.print(b + "\t");
        }
        
        System.out.println("\n"+"========中文字符gbk=========");
        byte[] gbk = str.getBytes("gbk");
        for (byte b : gbk) {            
            System.out.print(b + "\t");
        }
        
        System.out.println("\n"+"========英文字符gbk=========");
        byte[] gbk_en = en.getBytes("gbk");
        for (byte b : gbk_en) {            
            System.out.print(b + "\t");
        }
        
        String s = new String(utf8,"utf-8");
        String s1 = new String(utf8,"gbk");
        System.out.println("\n"+s + "====gbk:" + s1);
     }

测试上面方法,打印的结果是:

========中文字符utf-8=======
-28 -67  -96 -27  -91 -67  
========英文字符utf-8=======
104 63  104 
========中文字符gbk=========
-60 -29  -70 -61  
========英文字符gbk=========
104 63  104 
你好====gbk:浣犲ソ
------------------------------------------------------------------------------------

可以得出结论:

一个中文字符以utf-8编码会转成3个byte,如果以gbk编码会转成2个byte;

一个英文字符以utf-8编码会转成1个byte,如果以gbk编码会转成1个byte。

从打印的最后一行结合29-31行代码可以看出,如果把byte数组utf8 以utf-8的方式解码不会有乱码,还是原来的”你好“,而如果以gbk方式解码则出现了三个乱码字符,为什么是3个而不是2个呢,6/2=3。

接下来说iso-8859-1,这种编码应用于英文系列,也就是说不能表示中文(如果要使用必须依赖于其它兼容iso-8859-1编码方式的编码),它读不懂的字符都将被视为英文问号'?',英文问号的iso-8859-1编码号是:63(十进制)(其实在几乎所有的编码方式中,所有英文字符都用1个固定的字节码表示,unicode编码除外)。

     @Test
     public void testISO() throws Exception {
         String str = "你好";
         byte[] bs = str.getBytes("iso-8859-1");
         for (byte b : bs) {
            System.out.println(b);
         }
         System.out.println(new String(bs,"iso-8859-1"));
         System.out.println(new String(bs,"utf-8"));
         System.out.println(new String(bs,"gbk"));
         System.out.println(new String(bs,"unicode"));         
     }

打印结果 

63
63
??
??
??
㼿

说明63 =》?,所有中文都被认为是?,所以说当执行这句代码时:byte[] bs = "你好".getBytes("iso-8859-1");信息已丢失。

再执行String str = new String(bs,"任何charset");str已经不等于"你好"了,而是两个问号??。所以在tomcat中我们会经常遇上中文变为一长串??????,就是源于此。

在iso-8859-1、utf-8、gbk中一个字节码表示一个英文字符,

在unicode编码中一个字节码并不能表示任何字符,而且规定必须是两个字节码(有时4个)才能表示一个字符。

说了这么多,也许很多人会问为什么要用这么多编码方式,统一成utf-8不就能表示所有字符了?

编码不仅仅是要考虑是否能表示任何字符,还要考虑传输和存储。

1、utf-8确实几乎能表示所有已知字符。前面说过在utf-8编码中3个字节才表示一个中文字符,这样显然占空间,不利于传输和存储(传输和存储都是以二进制的方式进行的)

2、无疑一个字节表示一个字符最省空间,比如iso-8859-1。但这世上不是只有英文字符,还有各个地区国家的文字。所以字符的数量肯定是大于2的8次方的。

所以结合以上两点,就自然地出现了很多种编码方式。

了解各种编码方式的规则:https://jingyan.baidu.com/article/020278118741e91bcd9ce566.html

更多编程相关知识,请访问:编程教学!!

以上是中文乱码的产生原因是什么的详细内容。更多信息请关注PHP中文网其他相关文章!

声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
4 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
4 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
4 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.聊天命令以及如何使用它们
4 周前By尊渡假赌尊渡假赌尊渡假赌

热工具

DVWA

DVWA

Damn Vulnerable Web App (DVWA) 是一个PHP/MySQL的Web应用程序,非常容易受到攻击。它的主要目标是成为安全专业人员在合法环境中测试自己的技能和工具的辅助工具,帮助Web开发人员更好地理解保护Web应用程序的过程,并帮助教师/学生在课堂环境中教授/学习Web应用程序安全。DVWA的目标是通过简单直接的界面练习一些最常见的Web漏洞,难度各不相同。请注意,该软件中

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

螳螂BT

螳螂BT

Mantis是一个易于部署的基于Web的缺陷跟踪工具,用于帮助产品缺陷跟踪。它需要PHP、MySQL和一个Web服务器。请查看我们的演示和托管服务。

SublimeText3 英文版

SublimeText3 英文版

推荐:为Win版本,支持代码提示!

mPDF

mPDF

mPDF是一个PHP库,可以从UTF-8编码的HTML生成PDF文件。原作者Ian Back编写mPDF以从他的网站上“即时”输出PDF文件,并处理不同的语言。与原始脚本如HTML2FPDF相比,它的速度较慢,并且在使用Unicode字体时生成的文件较大,但支持CSS样式等,并进行了大量增强。支持几乎所有语言,包括RTL(阿拉伯语和希伯来语)和CJK(中日韩)。支持嵌套的块级元素(如P、DIV),