[概述]
在Windows操作系统中使用记事本新建一个文本文件,在文件里面写入“联通”两个字并保存。当再次打开这个文本文件时候,在记事本中看到得却不是刚刚输入的“联通”,而是乱码。网络上有人把这个奇怪现象包装成把戏,如果你曾遇到过这种把戏就会知道,他们往往让你建立两个文本文件进行对比,其中一个输入“联通”,另外一个可能是“移动”等等,最后试图八卦地让你相信联通、移动和微软之间有着种种恩怨情仇。
[解释]
这是一个字符编码应用的奇怪现象,讲的明白点,可以说是记事本开小差了!记事本为什么会犯错误?记事本犯了怎样的错误呢?也许你会迫不及待的想知道这些问题,如果是这样,我不会让你空腹而归的。
在简体中文操作系统中默认的本地字符集编码是GBK编码,除非你在保存记事本文本文件时候选择了其他编码方式,否则用记事本录入的字符信息将使用GBK编码进行储存。巧合的是,“联通”这两个字符的GBK编码具有UTF-8编码的特征,记事本犯下的错误正是将GBK编码存放的记录有“联通”两个字符的文件误认为UTF-8编码的文件。或许你会问,UTF-8编码的文件不是以“EF BB BF”三个特殊字节开头吗?既然这样,记事本怎么会犯这么低级的错误呢?没错,UTF-8编码规定使用UTF-8编码的文件以“EF BB BF”三个特殊字节开头,但并不是强制性要求,早期的UTF-8编码文件就不遵循这个规定。因此记事本不能依靠文件的开头字节判断一个文件是否是UTF-8编码,而只能对文件中的数据进行简单的编码分析来确定。正是这个原因,才有了字符编码应用中的这个奇怪又无法避免的现象。
[细节]
如果上面的解释对于你来说只是杯开胃红酒,那我还是块点把主食呈上吧,一份大峡谷香烤猪肋排。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 十六进制:C1 AA 二进制:1100 1101,1010 1000
请注意上面二进制数据的着色部分,你想到了什么?对,它们和UTF-8编码结构中的补充位完全一致,UTF-8编码的补充位使得编码值更有规律,而记事本刚好凭借这个特征区分UTF-8编码的文件。存有“联通”两个字符的文件的所有数据都符合这个特征,就是这样,记事本彻底的将文件误认为UTF-8编码的文件。
将错就错,让我们来看看这个错误是怎样收场的。如果把“联通”的GBK编码值当作UTF-8编码值,那文件就成为一个写有数据“C1 AA CD A8”并以UTF-8编码的文件,当使用记事本再次打开的时候会看到什么呢?只要将UTF-8编码转换成Unicode编码就知道了。UTF-8编码“C1 AA CD A8”转换成Unicode编码后,编码值为“6A 00 68 03”(转换方法请参考本Blog中的《字符编码》一文)。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值的结果)
分享到:
相关推荐
在开发一个简单的Java Web应用接口,用于删除包含中文字段的数据库记录时,开发者遇到一个奇怪的现象:尽管接口没有返回错误,但实际的数据并没有被删除。开发者尝试在本地环境中使用相同的代码执行删除操作,发现...
找到正确的配置文件后,可以将其复制到一个适合的位置,如 `/etc/my.cnf`,并进行编辑。使用文本编辑器(如 `vi`)打开该文件,并添加或修改以下配置项: ```ini [mysqld] default-character-set=utf8 [client...
这种现象往往发生在解压压缩包或导入特定格式文件(如CSV)到某些应用程序时。本文旨在针对Win11和Win10系统中的此类问题提供详细的解决方案。 #### 问题概述 中文文件名乱码现象主要发生在以下几种情况: 1. **解...
当涉及到中文字符时,如果没有正确处理字符编码,就可能出现乱码现象。以下是关于解决jquery向.ashx文件post中文乱码问题的详细知识点。 首先,从环境中可以看到,开发者使用的是Visual Studio 2005,并且由于未...
wangtengfei-hn_EmployeesExample_23540_1745868671962
scratch少儿编程逻辑思维游戏源码-汽车冲突.zip
scratch少儿编程逻辑思维游戏源码-棱镜.zip
少儿编程scratch项目源代码文件案例素材-直升机坠毁.zip
输入法优化与定制_五笔编码编辑与词库管理_Rime输入法引擎与86极点码表_跨平台五笔码表编辑器工具_for_macOS与Windows系统_支持用户自定义词条添加删除与排序_提供
少儿编程scratch项目源代码文件案例素材-主题乐园大亨.zip
scratch少儿编程逻辑思维游戏源码-迷失在像素平原.zip
少儿编程scratch项目源代码文件案例素材-纸格通关 云变量.zip
wanjunshe_Python-Tensorflow_12888_1745868924470
scratch少儿编程逻辑思维游戏源码-深入海底.zip
驾校自动化_网页自动化爬虫技术_Python27多线程HTTP请求模拟_龙泉驾校2014版约车系统自动预约助手_通过模拟登录和循环请求实现自动约车功能_支持失败自动递增车号重试_
scratch少儿编程逻辑思维游戏源码-南瓜危机.zip
scratch少儿编程逻辑思维游戏源码-皮博冒险者.zip
基于c++开发的网络嗅探器,重点对TCP、UDP、ARP、IGMP、ICMP 等数据包进行分析,实现捕捉前过滤、数据包统计、流量统计等功能+源码+项目文档,适合毕业设计、课程设计、项目开发。项目源码已经过严格测试,可以放心参考并在此基础上延申使用,详情见md文档 基于c++开发的网络嗅探器,重点对TCP、UDP、ARP、IGMP、ICMP 等数据包进行分析,实现捕捉前过滤、数据包统计、流量统计等功能+源码+项目文档,适合毕业设计、课程设计、项目开发。项目源码已经过严格测试,可以放心参考并在此基础上延申使用,详情见md文档~ 基于c++开发的网络嗅探器,重点对TCP、UDP、ARP、IGMP、ICMP 等数据包进行分析,实现捕捉前过滤、数据包统计、流量统计等功能+源码+项目文档,适合毕业设计、课程设计、项目开发。项目源码已经过严格测试,可以放心参考并在此基础上延申使用,详情见md文档 基于c++开发的网络嗅探器,重点对TCP、UDP、ARP、IGMP、ICMP 等数据包进行分析,实现捕捉前过滤、数据包统计、流量统计等功能+源码+项目文档,适合毕业设计、课程设计、项目开发。项目源码已经过严格测试,可以放心参考并在此基础上延申使用,详情见md文档 基于c++开发的网络嗅探器,重点对TCP、UDP、ARP、IGMP、ICMP 等数据包进行分析,实现捕捉前过滤、数据包统计、流量统计等功能+源码+项目文档,适合毕业设计、课程设计、项目开发。项目源码已经过严格测试,可以放心参考并在此基础上延申使用,详情见md文档
用于释放电脑的内存,很好用。
scratch少儿编程逻辑思维游戏源码-气球足球.zip