[概述]
在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值的结果)
分享到:
相关推荐
如果字符串的第一个字节小于0xEF,则认为该字符串使用的是默认编码;否则继续进行BOM检测,并根据检测结果返回相应的编码类型。 ```cpp if(ss[0] >= 0xEF) { if (ss[0] == 0xEF && ss[1] == 0xBB && ss[2] == 0xBF...
比如,一个GB2312编码的中文文档在UTF-8环境下打开,由于两者编码规则不同,计算机无法正确识别字符,导致显示异常。 为了解决这类问题,我们可以使用工具进行字符编码的自动识别和转换。"chartype"就是这样一个...
Unicode是一种国际化的字符编码标准,旨在为每种语言的每一个字符提供唯一的编码,从而避免不同编码标准之间的冲突。Unicode有两种主要的编码方式:UCS-2(Unicode-16)和UCS-4(Unicode-32)。UCS-2使用两个字节来...
下面是一个具体的示例代码,展示了如何在Struts2应用中配置一个名为`encodingfilter`的过滤器,并指定其作用于所有请求路径(`/*`)上。 ```xml <filter-name>encodingfilter <filter-class>org.apache.struts2....
字符编码是计算机科学领域中一个基础且重要的概念,它涉及到信息的存储、传输和处理。字符编码定义了如何将文字、符号等字符转换成二进制形式,以便计算机理解和处理。本文将深入探讨字符与编码的概念、发展历史、...
UTF-8是Unicode字符集的一个变种,是一种变长的字符编码方式。它使用1至4个字节来表示Unicode中的每个字符,其中英文字符只需要1个字节,而大部分汉字则需要3个字节。UTF-8具有良好的向前兼容性,广泛应用于网络...
编码生成后,程序将把每个字符的赫夫曼编码保存到一个编码文件中。为了实现这一点,可能使用了一个`CodeNode`结构体,包含了字符、编码位串和编码长度等信息。编码文件可能以某种格式存储,以便后续的解码过程能正确...
Unicode是一个全球通用的字符集标准,包含了世界上几乎所有的文字系统,使用统一的编码方式,避免了不同语言间的编码冲突。UTF-8是Unicode的一种实现方式,它是一种变长编码,可以高效地处理各种语言的文本。GBK是...
随着信息技术的发展,全球化的趋势要求计算机能够处理不同语言的文字信息,这就需要一个统一且兼容性强的字符编码方案。 #### 二、常见字符编码类型 1. **ASCII编码** - **简介**:ASCII(American Standard Code...
韩文字符编码总表
这里的 `new String(bytes, "UTF-8")` 表示创建一个新的字符串,该字符串的字符由指定的字节数组按照 UTF-8 编码转换而来。 #### 四、具体案例分析 根据题目描述中提到的内容,我们可以看到一些具体的场景应用: ...
标题“工具-字符编码转换”指的是一个用于处理字符编码转换的软件工具,它可能帮助用户在不同的字符编码之间进行转换,以解决不同系统或程序之间的兼容性问题。字符编码是计算机存储和显示文本的一种方式,常见的有...
总的来说,"完整版字符编码查看器"是一个实用的工具,对于开发人员、数据分析师、翻译工作者等涉及到文本处理的人员来说,它能够提供宝贵的帮助,深入理解并解决字符编码相关的问题。通过熟练运用这样的工具,我们...
计算机基础课件:西文字符的编码是一个复杂的编码系统,包括西文字符集、ASCII 码、扩充 ASCII 字符集、汉字编码、国标交换码、机内码等多个方面。只有深入了解这些概念和技术,才能更好地理解和应用计算机基础知识...
中文字符编码是计算机科学领域中的一个重要概念,尤其是在处理汉字和其他多语言文本时。这个压缩包“中文字符编码(ChineseCharacterCodes).zip”包含了五种主要的中文字符集,分别是Unicode、GB2312-80、GBK、Big 5...
UNICODE旨在提供全球范围内所有语言字符的统一编码方案,为每个字符分配了一个唯一的数字编码,使得跨语言、跨平台的信息处理成为可能。现代操作系统和编程环境广泛采用UNICODE,以支持全球化的字符集需求。 ##### ...
HTML特殊字符编码是网页设计与开发中不可或缺的一部分,它们用于在HTML文档中插入无法直接键入的字符,或者为了确保跨浏览器兼容性而使用的字符实体。以下是对标题、描述及部分给定内容中的知识点进行的详细解读: ...