记事本 BOM 之 “联通” "联" “联想” 为什么有的显示不正常

来源:互联网 发布:在线php编辑器 编辑:程序博客网 时间:2024/05/23 19:36
作者:TwinsForChina
链接:https://www.zhihu.com/question/25367290/answer/138972490
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

我们来做个测试

1. 用Windows记事本程序创建3个文件,分别输入“联想”,“联通”,“联”,然后分别保存

2. 再次打开

你可以看到什么了?是不是“联通”会消失了。一般我们在记事本里面写中文,保存的时候,默认应该是ansi格式的。输入“联通”之后,再次打开,记事本根据utf8的特征,误以为此文本是utf8的格式了。然后后面的事情便是一错再错了。如果是以utf8或者unicode的格式保存,再次打开,会是什么结果了?呵呵,自己看吧

我们来细说下吧

先看这个, UTF-8编码采用1-3个字节对字符进行编码,编码字节数与字符的Unicode编码值有严格的对应关系,让我们看下UTF-8编码和Unicode的对应关系吧。
Unicode编码值 UTF-8编码结构
\u0001 - \u007E 0XXXXXXX
\u0080 - \u07FF 和 \u0000 110XXXXX 10XXXXXX
\u0800 - \uFFFF 和1110XXXX 10XXXXXX 10XXXXXX

“联通”这两个字符的GBK编码值是“C1 AA CD A8",GBK编码方式使用两个字节对一个字符进行编码,因此以GBK编码方式存放的录有“联通”两个字符的文件的大小为四个字节。接下来分别观察“联通”这两个字符GBK编码值的二进制形式,你有发现有趣的事。
联 GBK 十六进制:C1 AA 二进制:1100 0001,1010 1010
通 GBK 十六进制:CD A8 二进制:1100 1101,1010 1000

请注意上面二进制数据的加粗部分,你想到了什么?对,它们和UTF-8编码结构中的补充位完全一致,UTF-8编码的补充位使得编码值更有规律,而记事本刚好凭借这个特征区分UTF-8编码的文件。存有“联通”两个字符的文件的所有数据都符合这个特征,就是这样,记事本彻底的将文件误认为UTF-8编码的文件。
将错就错,让我们来看看这个错误是怎样收场的。如果把“联通”的GBK编码值当作UTF-8编码值,那文件就成为一个写有数据“C1 AA CD A8”并以UTF-8编码的文件,当使用记事本再次打开的时候会看到什么呢?只要将UTF-8编码转换成Unicode编码就知道了(为啥要转成unicode咧,因为utf8是unicode的一种实现方式,只有unicode才有二进制和字符的对应关系)。

转换方法:让我们把第一个字节的110和第二个字节的10去掉,我们就得到了"00001 101010",再把各位对齐,补上前导的0,就得到了"0000 0000 0110 1010"。UTF-8编码“C1 AA CD A8”转换成Unicode编码后,编码值为“6A 00 68 03”。

0x006A这个Unicode编码值位于\u0001 - \u007E之间,若要转换为UTF-8编码,显然只能用一个字节进行编码,因此“联”的GBK编码“C1 AA”虽然特征上貌似UTF-8编码,但它却不对应任何一个UTF-8编码。接着看0x0368这个Unicode编码值,这个值对应了字符“ͨ”,这也正是我们将在记事本中看到的内容。或许你会说我看到的是一个黑色矩形啊,这只是字体的原因,你将字体改为宋体或者其他字体,看到的就是字符“ͨ”。


对于中文字符,UTF-8编码要用三个字节进行编码,因此,如果你使用记事本录入“联通”,然后选择以UTF-8编码方式保存的话,文件大小应为9个字节(包含三个字节的开头数据),而同样的文件GBK编码却是4个字节。最后附上“联通”的GBK、UTF-8、Unicode编码值,以及记事本的错误思维。

联通 GBK C1 AA CD A8 UTF-8 E8 81 94 E9 80 9A Unicode 54 80 1A 90
联通 GBK C1 AA CD A8 UTF-8 C1 AA CD A8 Unicode 6A 00 68 03 (将GBK值误认为UTF-8值的结果)

阅读全文
0 0
原创粉丝点击