听说你的程序又双叒叕乱码了

在我刚开始接触编程的时候,时不时就会遇到程序乱码问题。亦或是控制台输出乱码,亦或是数据库乱码,亦或是网页端显示乱码,总之乱码无处不在,它总是会在不应该出现的时间点出现在在不应该出现的位置。

那么乱码究竟是怎么回事呢,为啥好端端的文字就变成一堆乱七八糟的符号了呢?

这时如果你去网上搜索乱码问题,你就会发现大量的文章向你扑面而来,看完之后你更加郁闷了,还是不明其中缘由,今天我们就来探究下程序究竟为什么会乱码?

ASCII 码

大家都知道计算机是从美国开始走向全世界的,最初的用途是服务于美国军方,用来帮助人类做一些复杂的数学运算,比如计算导弹弹道之类的。

后来随着计算机的发展,人们发现这个工具简直太好用了,事实再一次证明人类是多么的贪婪。他们有了更多的需求和欲望,比如想让计算机处理文字,控制打印机等。这时候就不像处理数学运算那么简单了,因为计算机内部都是 0 和 1 的二进制代码,怎么才能让计算机显示文字呢,于是发明计算机的大叔们搞了一个字符和数字的对应关系。我们知道虽然单词有很多个,但每个单词都是由 26 个字母组成的,区分大小写的话也才 52 个,1 个字节 8 位可以有 256 种状态,再加上数字和一些标点符号 1 个字节也足够了。

于是那些大叔们把从 0 开始的 32 种状态规定了特殊的用途,比如打印机换行,彩色打印。然后又把数字、标点符号、大小写字母等逐一编码,直到编写到 127 号,也就是共计 128 个编码。最后给这张编码表起了个逼格很高的名字,叫「ASCII 码」,也叫「美国信息交换标准代码」(American Standard Code for Information Interchange)。

比如,小写字母 a 对应的 ASCII 码值是 97,十六进制 0x61;数字 0 对应的 ASCII 码是 48,十六进制 0x30。「ASCII 码」是计算机编码的基石。后面所有的编码都是在此基础上完善的。

GBK 编码

后来随着时代的不断发展,计算机在全球范围内开始普及。日本,俄罗斯,中国等很多国家都开始使用计算机,但其他很多国家用的并不是英文呀,比如我们中国的汉字,跟英文的字母简直是天壤之别,而且仅常用的汉字就要有 3000+ 了,1 个字节 256 种状态怎么够用呢。

于是聪慧的中国人民发明了我们自己的编码系统,用两个字节来表示一个汉字或者字符。第一个字节称为「高位字节」(也称区字节),第二个字节称为「低位字节」(也称位字节)。但这两个字节是有限制的,「高位字节」使用范围为 0xA1-0xF7,「低位字节」使用范围为 0xA1-0xFE

这样我们就可以组合出大概 8000 个左右的汉字了,对于日常使用来说是足够了。这套编码规则就是「GB2312」。

你知道的,中国文化博大精深,区区 8000 个汉字怎么够用,很多少数民族也迫切希望用上计算机,很多人名依然无法识别,于是不在对高位字节和低位字节做限制,只要发现第一个字节大于 127 就认为这是一个汉字的开始,为什么要大于 127 呢,因为要兼容「ASCII 码」呀,127 以内说明是该字节表示的是「ASCII 码」。

这样子 2 个字节 15 位大概可以表示 65536 - 127 个汉字。

然而香港和台湾并没有使用大陆的 GBK 编码规则,因为他们使用繁体字,所以就单独设计了一套自己的编码系统,叫做「Big5」表,也叫大五码或者五大码。

然后日本、韩国等不同国家也都设计了自己独有的编码规则,因为是各自独立设计,所以大概率不会出现一个字符在不同的编码系统中对应同一个数字。于是就会出出现乱码这种很诡异的现象。

比如,你的韩国女朋友给你发了一封电子邮件,里面的真实内容为「么么哒」,由于电子邮件是在韩国写的,所以计算机肯定是使用韩国的编码系统,假设这三个字对应的编码分别是 0xA6B2、0xA6B2、0xC132;当你收到邮件之后,因为你是在国内所以肯定是使用 GBK 编码来解码,那么将三个编码转换为汉字之后发现是「分手吧」。

相信此时的你肯定是一脸懵逼,然后就又开始怀疑是不是自己做错了什么。

天下大统

为了解决各国编码不统一的问题,国际标准化组织制定了一套新的规则,叫做「Unicode码」,这套编码规则就厉害了,可以将全人类所有的字符都包含进去,包括人类走出非洲时的所使用的象形文字都可以包含进来。

那么如果要想包含这么多的字符进来的话,至少需要三个字节才可以,三个字节可以存储三百多万个字符,这应该可以覆盖所有文化的字符了吧,如果还不够的话,就用四个字节来表示一个字符,这样可以组合出大概 21 亿个字符,可能用到地球毁灭那一天都用不完。

可是随之而来的是另外一个问题,由于欧美大多使用英文,一个字节足以表示,现在让他们用三个字节,就造成了空间的巨大浪费。浪费率高达 2/3,做过网络编程的小伙伴们都知道,在网络中数据的传输是需要很大的成本的,而且还不可靠,字节数越多,浪费的资源也就越多。

于是,在接下来的时间内,出现了多种「Unicode码」的具体编码方式,分别是 UTF-8、UTF-16、UTF-32,其中 UTF-8 占用一到四个字节,UTF-16 占用二到四个字节,UTF-32 占用四个字节。显然 UTF-8 的设计更合理,欧美字符用一个字节来存储,中文或者其他字符用二个或者三个字节来存储,岂不美哉。

自此,天下大统。呃,不,是计算机编码得以大统,世上在无乱码。

总结

今天我们详细介绍了编码的历史,以及乱码的缘由,下次遇到乱码问题再也不慌了。

Python Geek Tech wechat
欢迎订阅 Python 技术,这里分享关于 Python 的一切。