奇怪的联通现象

        作为开发人员,或许听说过“奇怪的联通现象”。没有听说也没有关系,那什么是“联通现象”?到底是什么原因造成这个现象产生呢?本文帮你解疑答惑。

        有个很著名的奇怪现象:当你在 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进制的内容转成二进制

进制转化可以通过在线进制转换工具实现。https://tool.lu/hexconvert/

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

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进制

        进制转化可以通过在线进制转换工具实现。https://tool.lu/hexconvert/  

     (二进制转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打开后就显示正常的文字了。

你可能感兴趣的:(奇怪的联通现象)