相信大家平时工作和生活中,都遇到过乱码的现象。比如PDF格式的文件复制粘贴到Word文件中,很容易出现错误,影响对文件的识别。那么这种现象是如何产生的呢?
最早广泛使用,名气最大的编码方式当属ASCII(美国标准信息交换码)。众所周知,计算机内部的所有信息最终都是一个二进制值。每一个二进制位(bit)有0和1两种状态,因此八个二进制位就可以组合出256种状态,这也被称为一个字节(byte)。也就是说,一个字节可以表示256种不同的状态,每一个状态对应一个符号,就是256个符号。
ASCII码由一张主表和一张扩展表组成,如下图,图源网络。
使用WinHEX以16进制打开内容为“AB”的ASCII编码方式的文本文件,可以看到其值为0x41、0x42对应十进制的65、66,符合上表内容。
ASCII码表对于以英语为母语的国家来说,足够用了。但对于其他国家来说,明显是不能满足需求的。所以,在计算机传入中国以后,中国专家制定了GB2312/GB2312-80编码。
由于扩展ASCII码表不常用,中国专家整合了扩展ASCII码表(即128-255)并进行了重新编码,规定:一共小于127的字符的意义与原来相同,但当两个大于127的字符连在一起时,就表示一个汉字,这样我们就可以组合出大约7000个简体汉字。上述编码规则就是GB2312或GB2312-80(国标码)。
经过对本来ASCII里就有的数字、标点、字母进行两个字节场的重新编码,就形成了常说的"全角"字符,而原来小于127号的那些就叫"半角字符"。
使用WinHEX以16进制打开内容为“AB中国”的GB2312编码方式的文件,可以清楚的看到A、B仍然存储为0x41、0x42;“中”和“国”均由2个处于0x80-0xFF的十六进制数(对应十进制的128-255)表示。
GB2312/GB2312-80包含了大部分常用汉字。然而在生产生活中,我们时不时的会使用到一些生僻字,在此基础上就诞生了GBK编码。
GB2312支持的汉字太少。1995年的汉字扩展规范GBK1.0收录了21886个符号,它分为汉字区和图形符号区。其中汉字区包括21003个字符。
从ASCII、GB2312到GBK,这些编码方法是向下兼容的,即同一个字符在这些方案中总是有相同的编码,后面的标准支持更多的字符。在这些编码中,英文和中文可以统一处理。字符不论中英文均使用双字节来表示,只不过为了区分中文,才将其最高位都定成1。
由于GBK与GB2312和SCII编码兼容,所以在常用字符上,二者编码一致,为避免重复,此处不在图上详细讲解。
GBK编码很好地满足了我们国家民众的需求,但这种方式也有其弊端。如跨国交流的时候,像中国和日本、韩国等使用象形文字的国家之间,传送文件后仍会出现乱码现象。在此种情况下,Unicode应运而生。
Unicode是一个编码方案,说白了就是一张包含全世界所有文字的一个编码表,只要这个世界上存在的文字符号,统统给你一个唯一的编码。Unicode编码范围是: 0-0x10FFFF,可以容纳100多万个符号。
Unicode其实更像是一个符号集,它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储。
Unicode 编码共有三种具体实现,分别为UTF-8,UTF-16,UTF-32。我们平时所说的Unicode 编码默认是指UTF-16编码。
UTF-16编码以16位无符号整数为单位,注意是16位为一个单位,不能一股脑地认为UTF-16编码就是16位;这个要看字符的unicode编码处于什么范围而定,有可能是2个字节,也可能是4个字节。
同样以内容为“AB中国”的文本文件为例,最前面的“FF FE”被称为BOM,这个下文会提到,先不谈。可以看到即便是A、B这种原本只用一个字节能表示的字符,也仍旧占据了两个字节。
在本地还好,只是浪费点磁盘空间,但是在网络传输时,十分占用资源,尤其对英语母语的国家而言。
UTF-32是对Unicode编码的最简单粗暴的实现方式,即每个字符均有4个字节表示。UTF-16尚且算浪费资源,更何况UTF-32呢?由于其过于浪费资源,使用范围很窄,本文在这里就不详谈了。
那么有没有一种比较省资源的编码方式呢?答案是有,即UTF-8编码。
UTF-8是一种非常灵活的编码方式,其根据字符在Unicode编码中的位置来决定其由几个字节组成。对应关系如下表:
Unicode编码(16进制) | UTF-8字节流(二进制) |
---|---|
000000 - 00007F | 0xxxxxxx |
000080 - 0007FF | 110xxxxx 10xxxxxx |
000800 - 00FFFF | 1110xxxx 10xxxxxx 10xxxxxx |
010000 - 10FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx |
同样以内容为“AB中国”的文本文件为例,最前面的“EF BB BF”被称为BOM,先忽略。字符A、B处在000000 - 00007F范围内,所以仍为0x41、0x42,很容易理解。难点在"中"和"国“的编码。
以”中“为例,“中”的Unicode编码为4E 2D,处于000800 - 00FFFF范围内。将4E 2D化为二进制“0100 1110 0010 1101”,按照上表中第三行右侧的情况分组,然后在最前面填充“1110”、“10”、”10“,最后在重新转成16进制即可。“国”同理,由兴趣的读者可以尝试推导下。
4 E 2 D
0100 1110 0010 1101
0100 111000 101101
11100100 10111000 10101101
E4 B8 AD
因为UTF-8编码方式灵活,所以相应的其解码所需的时间也比UTF-16和UTF-32要长。
BOM(Byte Order Mark),字节顺序标记,出现在文本文件头部,Unicode编码标准中用于标识文件是采用哪种格式的编码。
以UTF-16和UTF-8为例:
编码格式 | 文件起始标识 |
---|---|
UTF-8 | EF BB BF |
UTF-16LE(小端存储) | FF FE |
UTF-16BE(大端存储) | FE FF |
大端存储与小端存储模式主要指的是数据在计算机中存储的两种字节优先顺序。
例如要表示0x12345678
偏移地址: 0x 00 01 02 03
小端存储: 78 56 34 12
大端存储: 12 34 56 78
尽管编码方式多种多样,现实生活中仍需灵活选择。若选择国际通用,则选择UTF-8编码;若仅仅是国内使用,则选择GBK编码(因为UTF-8中汉字占了3个字节,反而浪费了空间)。其他编码,可以自取所需。
此外,若遇到乱码问题,可以使用Windows平台内置的记事本notepad.exe.打开文件后,点击文件菜单中的“另存为命令”,点击对话框最底部编码的下拉条,保存即可。
本文作者 r0fus0d、the-fog
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。