admin管理员组

文章数量:1122944

【UTF

小伙伴们大家好,我是低调儒雅的Steven老师,作为开发人员,或许听说过“神奇的联通乱码现象”。没有听说也没有关系,那什么是“联通乱码现象”?到底是什么原因造成这个现象产生呢?

本文帮你彻底答疑解惑,当你理解“联通乱码现象”的根源后,其实也就真正加深了对中文乱码的解决之道。

有个很著名的奇怪现象:当你在 windows系统 的记事本里新建一个空白文件,在文件里输入"联通"两个字之后保存,关闭文件后再双击打开。观察到什么了吗?输入“力挺联通”,保存后再双击打开,又会如何呢? 

输入“联通”两个字的时候:             

输入文字时是正常的

保存并关闭文件,双击打开后的结果:     

双击打开记事本,显示乱码

输入“力挺联通”四个字的时候:          

输入文字时是正常的

保存并关闭文件,双击打开后的结果:          

双击打开记事本,显示乱码

你会发现,明明输入的是正确的文字,但是关闭后再双击打开文件,发现文字消失,取而代之的是几个乱码!为什么会这样呢?

大家知道,记事本是微软的产品。莫非联通得罪了微软?

为了能透彻理解这个奇怪的现象,一定要透彻理解字符编码,尤其是UTF-8编码格式。

接下来让我们来分析一下计算机对UTF-8文件的解码过程。掌握了UTF-8文件的解码过程,那么就具有了解释“奇怪的联通现象”的技术基础了。

好吧!说干就干。

有一个UTF-8编码的文本,文本内容为:“a0一” 。

分别是英文字母“a”,数字“0”,中文汉字“一”。接下来我们来分析一下这个文件,计算机是如何识别的吧。

一.获取十六进制编码的内容

在这里介绍一个软件:UltraEdit文本编辑器。用这个软件,可以查看文本的十六进制代码。

 

        

建议安装软件UltraEdit 

在UltraEdit编辑器中输入文本“a0一”

文本“a0一”的16进制

1、在文本编辑区输入内容

2、选择字符编码格式

3、点击“16进制编辑”按钮,查看文本内容的16进制

所以,获取到“a0一”的16进制为:

            61    30    E4    B8    80

二.将16进制的内容转成二进制

进制转化可以通过在线进制转换工具实现      

通过在线工具进行进制转换

1、输入网址

2、选择进制

3、在文本框输入内容

4、点击“转换”按钮

5、查看对应进制的内容

所以16进制:61    30    E4    B8    80

转成二进制后如下:(不足8位长度的在数字前端补0)

01100001 

00110000

11100100

10111000

10000000

每8个数字代表一个字节,所以能看出该文本共有五个字节。但是到底哪几个字节是一个字符单元呢?计算机是如何分组的呢?

因为该文件保存的格式是UTF-8编码格式,我们来回顾一下UTF-8编码的特点:

1、UTF-8编码是可变字节编码。所以每8个字节并不一定就是一个字符。有可能8个字节是一个字符,有可能16字节是一个字符,有可能24字节是一个字符。

2、文本读取是一个字节一个字节的来读取,根据字节开头的标志位来识别,从而能确定到底几个字节是一个字符单元。

3、UTF-8编码规则中,原Unicode前128个字符是单字节编码(实体编号在127以内),编号在128至2047的是双字节编码(2的11次方=2048),编号在2048之后就是三字节编码。

(1)如果字节的第一位是0,则说明这个字节是单字节;

(2)如果第一个字节的前3位是110,第2个字节的前2位是10,符合这个规律的连续相连的两个字节就代表一个双字节的字符;

(3)如果第1个字节的前4位是1110,第2个字节的前2位是10,第3个字节的前2位是10,符合这个规律的连续相连的三个字节就代表一个三字节的字符。

UTF-8编码的二进制格式

三.根据UTF-8编码规则以上二进制内容被分为三个组:

01100001     第一个字符

00110000     第二个字符

11100100      以下三个字节是一个中文字符,符合1110xxxx 10xxxxxx 10xxxxxx的格式

10111000

10000000

四.重新计算,得出对应Unicode字符集的二进制编码

Unicode字符集是双字节编码,所以每16位数字代表一个字符。

删除标记位上的数字,将剩余的二进制数字合在一起,不足16位的,在数字前补足0。根据这个规则,以上二进制数字就变成了以下三组二进制的数字。

00000000  01100001      第一个字符

00000000  00110000      第二个字符

01001110  00000000       第三个字符 

五.将上述三组二进制数字转成10进制

进制转化可以通过在线进制转换工具实现。  

(二进制转10进制时,要将0或1之间的空格去除,再通过工具进行转换。)

上述二进制对应的十进制数字为:

97

48

19968

六.通过10进制反查在Unicode字符集中它们对应的字符

97、48、19968其实就是Unicode字符集中字符的索引下标。Unicode字符集中索引为97的符号是哪个呢?其实熟悉ASCII表的同学都知道,是小写字母“a”。不熟悉的话也没有关系,我们可以通过以下方式来查看。

新建一个html文件,在文件中输入:

a0一

&#实体编号;——这种格式是html的实体编码格式。写好后保存关闭文件,然后双击打开,我们可以在浏览器中看到显示内容:a0一 

展示html文件的内容

掌握了计算机对UTF-8文件的解码过程,接下来我们来解释奇怪的“联通”乱码问题吧

当新建一个文本文件时,记事本的编码默认是ANSI,在ANSI编码格式的文件里输入汉字,那么实际就是GB2312编码格式。在这种编码下,"联通"的十六进制编码是:C1 AA CD A8       

   

在UltraEdit编辑器中输入文字“联通”

“联通”两个字的16进制

将C1 AA CD A8转成二进制后:

11000001

10101010

11001101

10101000  

UTF-8文字的二进制格式

大家有没有发现,这个GB2312文件的二进制数字格式竟然与UTF-8的二进制格式巧合地撞车了。

虽然保存的是GB2312编码,但是“联通”这两个字的二进制数字正好和UTF-8的格式完全吻合,所以记事本就把这个文件当做UTF-8编码格式了,自然就以UTF-8编码方式来打开并解码了。根据UTF-8编码规则,以上二进制内容被分为两个组,内容为:

0000000001101010

0000001101101000

转为10进制后为:106和872,Unicode字符集中第一个中文字“一”,序列号是19968,所以106和872这明显不是中文。

奇怪的联通现象,出现乱码的主要原因是:GB2312编码与UTF-8编码产生了编码冲撞,导致编码误解,从而触发了错误的文件打开方式所引起。

如果输入中文"爱联通",保存文件后关闭,当再次打开,则不会出现乱码问题。因为中文“爱”在编码表中对应的二进制数据不符合UTF-8的格式,所以记事本不会误解该文件是UTF-8编码格式,就会用默认的GB2312编码来解码,自然就不会出现乱码。其实在“联通”两个字前或后多输入几个字,就不会出现这样的巧合了。

那么输入“力挺联通”四个字是不是就不会这么巧合而乱码了呢?

非常奇妙的是输入“力挺联通”,还会出现乱码。原因是“力挺”这两个字的GB2312二进制编码也恰好与UTF-8吻合。

整个文件里的四个字都是符合UTF-8编码格式的,自然就会被误解为UTF-8编码的文件,那么双击打开时就会采用UTF-8编码方式来解码。

巧吧!       

    

在UltraEdit编辑器中输入“力挺”

更改编码格式为GB2312

“力挺”两个字的16进制是:C1 A6 CD A6

C1 A6 CD A6

转成二进制后:

11000001

10100110

11001101

10100110

这也符合UTF-8编码的格式。

总之,只要GB2312文本的二进制编码不与UTF-8格式完全吻合,就不会被误解是UTF-8文件,也就不会因为误解而采用错误的编码方式来解码了。

其实换一种文本编辑器来打开,乱码问题就可以避免。如果没有专业的文本编辑器,甚至使用浏览器来打开,也能正常显示出中文内容。本文采用EditPlus来打开该文件。

当采用正确的编码格式来打开,原本被认为是乱码的文件就正常显示了。

       

例如采用EditPlus文本编辑器来打开 

直接双击用记事本打开,显示为乱码的文件,当采用EditPlus打开后就显示正常的文字

*威哥Java学习交流Q群:691533824
加群备注:CSDN推荐

本文标签: UTF