原文链接:https://zhuanlan.zhihu.com/p/258345888
感谢原作者的分享~本博客仅仅是为了做笔记
计算机是美国人发明的, 早期在处理文字方面, 美国人很自然地只考虑处理英语世界的文字.
现在我们知道, 计算机一次性至少处理8位二进制数, 称为一个字节. 现在所说的16位CPU, 32位CPU, 64位CPU都是以8为基数按照倍数进行扩展的.
对于一个字节来说, 不考虑负数, 8位二进制数转换为十进制数相当于0至255, 总共256个数字. 但对于英文来说, 当年的美国工程师认为26个大小写字母, 加上数字, 标点符号, 空格, 特殊的控制字符等, 也不过127个以内, 严格来说只需要7位二进制数就可以完全覆盖. 所以, 对于用8位二进制数处理英文, 最高位永远是0, 取值范围是从00000000到01111111. 这就是ACSII编码/字符集.
随着计算机在全世界广泛应用, 如何处理当地语言文字称为头一号问题. 80年代, 中国大陆的国家标准总局根据ACSII进行了扩充, 用于处理简体中文. 这个标准叫做GB2312.
GB2312对ACSII的扩充方法很简单. 由于ACSII的最高位永远是0, 那么最高位是1的就表示扩展码, 当程序读到文本的最高位是1时就把下一个字节组合在一起表示一个字符. 因此, GB2312完全兼容ACSII编码, 英文字母和半角标点符号等用一个字节表示, 而ACSII以外的字符, 如汉字, 全角标点符号, 则统一使用两个字节表示.
GB2312虽然能覆盖99.5%的使用场景, 但只考虑了常用的简体中文, 总共收录的汉字也不到7000个. 而两个字节理论上可以存储6万5千个左右的字符, 因此GB2312有大量空间是闲置的. 同时期, 港澳台地区使用的是BIG5, 日韩也是各自有自己得一套规则. 于是, 1995年国家有关机构基于GB2312继续扩充, 推出了GBK, 把所有空闲空间都填充完毕, 不但涵盖了BIG5定义的繁体中文, 也收录日韩文字.
所以, GBK是完全兼容GB2312的, 自然也兼容ACSII, 几乎满足汉字文化圈的需要了.
到这里, 计算机处理当地语言文字的问题得到了妥善解决, 但现在又遇到国际之间如何通信的问题. 由于编码规则不同, 各国/各地区对同一个数字所代表的字符是截然不同的, 因此用A国计算机编写的文本给B国计算机打开, 很可能就是无法阅读的乱码.
这个时候, 国际标准化组织推出了unicode, 旨在收录人类目前已知在使用的所有字符, 给它们进行统一的分类和编号.
unicode的出现使得字符集和编码规则出现区分. unicode只是字符集, 只负责给字符编号, 不规定具体应当如何编码存储. 而此前, 无论是ACSII,GB2312, 还是GBK,BIG5等, 本身既是字符集, 也是编码规则.
UTF-8, UTF-16, UTF-32就是对unicode的编码规则了.
UTF-8属于变长编码规则, 字符的长度可能在1至6个字节之间. 对于英文来说, 只需要一个字节就足够了, 而对大多数汉字来说, 则需要三个字节. 具体长度取决于字符在unicode编码的哪个区间内, 这里不展开说了.
UTF-8规定, 最高位是0开头的, 就用一个字节表示, 而ACSII正好在其中, 因此UTF-8也是兼容ACSII的. 最高位是110开头的, 就与后一个以10开头的字节拼接为一个整体. 最高位是1110开头的, 就与后两个以10开头的字节拼接为一个整体. 以此类推.
UTF-16则使用两个字节表示unicode, 期间还涉及大小端如何摆放的问题, 具体规则不表.
UTF-32使用4个字节表示unicode, 属于定长编码规则. UTF-32的优点是完全根据unicode指定的编号进行编码, 不需要做额外的解析工作, 缺点是常用的字符有大量高位是被0填充的, 浪费存储空间.
由于全世界有数百种编码规则, 各有各的名称, 所以为了便于统一管理, 各国家, 地区, 标准化组织向美国有关机构提交自己编码规则, 并进行了统一编号. 例如GBK的页码就是956, UTF-8的页码就是65001. 这样, 人们就不需要在数百种不明所以的名称中去找所需的规则了.
然而, 在Windows上, 特别是Windows10之前的版本, 用户在选择编码规则时, 常常会同时出现UTF-8和Unicode这两个选项, 按道理说, Unicode只是字符集, 不应该出现在编码规则中, 这是怎么回事呢? 原来, 微软默认把Unicode当作UTF-16进行处理, 所以这里的Unicode就相当于选择了UTF-16, 是不是很坑爹?