建议收藏,彻底搞懂字符编码问题,从此告别中⽂乱码
在中⽂的语⾔环境⾥,⾝为程序员的我们⼀定会遇到过中⽂乱码的情况,究其原因就是字符编码的问题。在没有深⼊理解其原理之前,会觉得中⽂编码问题⽐较谜,莫名其妙地乱码,⼜稀⾥糊涂地好了。
字符编码是计算机技术的基⽯,本⽂希望帮助⼤家彻底梳理清楚字符编码问题,不仅知其然,还知其所以然,摆脱被中⽂乱码⽀配的感觉。
在讲解中⽂编码问题之前,我们需要先讲讲英语编码,其解决⽅案是 ASCII。
ASCII
ASCII 的英⽂全称是 American Standard Code for Information Interchange,中⽂意思是美国信息交换标准代码,是基于拉丁字母的⼀套计算机编码系统,使⽤ 8 位⼆进制表⽰字符。
在计算机内部,所有信息最终都是⼀个⼆进制值。每⼀个⼆进制位(bit)有 0 和 1 两种状态,因此 8 个⼆进制位就可以组合出 256 种状态,这被称为⼀个字节(byte)。
换句话说,⼀个字节可以表⽰ 256 种不同的状态,每⼀个状态对应⼀个符号,也就是 256 个符号,从 0000 0000 到 1111 1111,其数量计算公式:。
列举⼀部分 ASCII 码表,如下所⽰:
英语是由 26 个基本拉丁字母、阿拉伯数字和英式标点符号组成,因此⽤ 128 个符号就⾜够了,但 ASCII 码对于其他⼀些复杂的语⾔,就⼒不从⼼了,⽐如:汉字⼤约将近 10 万个(虽然没有准确的数字,但⽇常使⽤汉字也有⼏千字)。
⼀个字节只能表⽰ 256 种符号,肯定是不够的,就必须使⽤多个字节表达⼀个符号。为了正确显⽰中⽂字符,在 1981 年 5 ⽉ 1 ⽇,由中国国家标准总局发布了《信息交换⽤汉字编码字符·基本集》,通常简称 GB。
GB 类
中国⼤陆⼏乎所有的中⽂系统和国际化的软件都⽀持 GB2312。GB2312 是简体中⽂常见的编码⽅式,使⽤两个字节表⽰⼀个汉字,所以最多可以表⽰ 个符号。
GB2312 标准共收录 6763 个汉字,其中⼀级汉字(常⽤字)3755 个,⼆级汉字(较不常⽤)3008个,同时收录了包括拉丁字母、希腊字母、⽇⽂平假名及⽚假名字母、俄语西⾥尔字母在内的 682 个字符。
GB2312 基本满⾜了计算机处理简体汉字的需求,所收录的汉字覆盖了 99.75% 的使⽤频率,但对于罕见字和繁体字,GB2312 就不能处理了。因此发明了后来的 GBK 和 GB18030。它们之间的关系如下图所⽰:
GBK 编码是 GB2312 编码的超集,向下完全兼容 GB2312,兼容的含义是不仅字符兼容,⽽且相同字符的编码也相同。⽽ GB18030 编码向下兼容 GBK 和 GB2312,GB18030 编码是变长编码。
但很多像 GB 类的编码⽅式都有⼀个共同的问题,允许计算机处理双语环境,即拉丁字母和本地语⾔,却⽆法同时⽀持多语⾔环境,即多种语⾔混合的情况。Unicode 就是为了解决这个问题⽽诞⽣的⽅案。
Unicode
世界上存在着多种语⾔,⽐如:西班⽛语、韩语、俄语等等,它们也都分别有各⾃的编码⽅式,所以同⼀个⼆进制数字可以被解释成不同的符号。如果想要正确的打开⼀个⽂本⽂件,就必须知道它的编码⽅式,否则就会出现乱码。
假如有⼀种编码,将世界上所有的符号都纳⼊其中。每⼀个符号都给予⼀个独⼀⽆⼆的编码,那么乱码问题就会消失。这就是 Unicode,⼀种所有符号的编码。
Unicode 伴随着通⽤字符集的标准⽽发展,当前最新的版本为 2019 年 5 ⽉公布的 12.1.0,已经收录超过 13 万个字符。Unicode 涵盖的数据除了视觉上的字形、编码⽅式、标准的字符编码外,还包含了字符特性,如⼤⼩写字母。
然⽽,Unicode 只是⼀个符号集,不代表计算机⾥的编码,它只规定了符号的⼆进制代码,却没有规定这个⼆进制代码应该如何存储。因此,导致了两个问题:
计算机怎么知道三个字节表⽰⼀个符号,⽽不是分别表⽰三个符号呢?
英⽂字母只⽤⼀个字节表⽰就够了,但按照 Unicode 规定,每个符号要⽤ 3 个或 4 个字节表⽰,那么英语⽂本的存储空间将扩⼤ 3到 4 倍,是极⼤的浪费。
随着互联⽹的发展,不同国家的信息越来越多地在⽹络中传播,强烈需要⼀种统⼀的编码⽅式,UTF-8 就是在互联⽹上被⼴泛使⽤的⼀种Unicode 实现⽅式。
UTF-8
再次强调⼀下,UTF-8 是 Unicode 的实现⽅式之⼀,并不是唯⼀,也不等同于 Unicode。除了 UTF-8,还有 UTF-16 和 UTF-32,只是很少被使⽤。
UTF-8 的特点是对不同范围的字符使⽤不同长度的编码,它可以使⽤ 1~4 个字节表⽰⼀个符号,根据不同的符号⽽变化字节长度。其编码
规则很简单:
对于单字节的符号,字节的第⼀位设为 0,后⾯ 7 位为这个符号的 Unicode 码。因此对于英语字母,UTF-8 编码和 ASCII 码是相同的。
对于 n 字节的符号(n>1),第⼀个字节的前 n 位都设为 1,第 n+1 位设为 0,后⾯字节的前两位⼀律设为 10,剩下的没有提及的⼆进制位,全部为这个符号的 Unicode 码。
Unicode 与 UTF-8 的字节对应关系:
以“爱”为例,其的 Unicode 是 U+7231,是在 U+0800~U+FFFF 范围内,所以采⽤ 3 个字节进⾏编码,其⼆进制为 01110010 00110001。那么⽤ UTF-8 表⽰,则如下图所⽰:
后记
计算机操作系统中的编码:
Windows下中⽂的默认编码是 GBK(GB2312)。
Linux 下中⽂的默认编码是 UTF-8。
如果使⽤的是 Linux 系统,可以通过如下命令,查看系统中⽂编码:
1echo $LANG
2en_US.UTF-8
如果想要查看⽂件的原始编码,并且转换编码,可以使⽤ enca 命令,可以通过 apt-get install enca 进⾏安装。
1enca -L zh_CN <file> # 查看⽂件的编码
2enca -L zh_CN -x UTF-8 <file> # 将⽂件编码转换为UTF-8编码
3enca -L zh_CN -x UTF-8 <file_1> <file_2> # 保留原始⽂件
字符编码选择建议:
1. 只有英⽂,选择 ASCII。
unicode码和ascii码区别2. 主要存中⽂,对存储⼤⼩⽐较敏感,选择 GB2312。
3. 通⽤性第⼀,处理简单,选择 UTF-8。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论