计算机编码简析
ISO-8859-1:又称“西欧语言”;可使用的语言例如:荷兰语、西班牙语、德语、意大利语等。
ISO-8859-2:又称“中欧语言”;可使用的语言例如:克罗地亚语、捷克语、匈牙利语、波兰语等。
ISO-8859-3:又称“南欧语言”;可使用的语言例如:世界语、马耳他语等。
ISO-8859-4:又称“南欧语言”;可使用的语言例如:爱沙尼亚语、格陵兰语、拉脱维亚语等。
这也说明了 ISO-8859 不是一个字符集方案,而是一个系列的字符集方案,同样的码位可以映射不同的字符集。
作为中国人,我们在使用计算机的时候,自然的会使用到汉字,而上述提供的 ASCII 和 ISO 中,都不支持汉字的字符,所以国内也搞了一套方案。
汉字有上万字,但是常用的只有几千个,最最常用的也就 3000 个左右。
2.2.1 GB 2312
GB 2312 标准共收录 6763 个汉字,其中一级汉字 3755 个,二级汉字 3008 个;同时,GB 2312 收录了包括拉丁字母、希腊字母、日文平假名及片假名字母、俄语西里尔字母在内的 682 个全角字符。
每个汉字及符号以两个字节来表示。第一个字节称为“高位字节”(也称“区字节)”,第二个字节称为“低位字节”(也称“位字节”)。
区字节含义:
GB 2312 中对所收汉字进行了“分区”处理,每区含有 94 个汉字/符号。这种表示方式也称为区位码。
01-09 区为特殊符号
16-55 区为一级汉字,按拼音排序
56-87 区为二级汉字,按部首/笔画排序
10-15 区及 88-94 区则未有编码。
举例来说,“啊”字是 GB2312 之中的第一个汉字,它的区位码就是 1601。
汉字区的内码范围高字节从 B0-F7(176-247),低字节从 A1-FE(161-254),占用的码位是 72*94=6768,其中有 5 个空位是 D7FA-D7FE。
例如“啊”字在大多数程序中,会以两个字节,0xB0(第一个字节) 0xA1(第二个字节)储存。区位码=区字节+位字节(与区位码对比:0xB0=0xA0+16,0xA1=0xA0+1)。
2.2.2 GBK
尽管 GB
2312 收录了总共 6000 多个汉字,但是这仍然比较少,还不能覆盖到绝大多数场景的需求。
在 1995 年,国家出台了 GBK(《汉字内码扩展规范》国标扩展的英文简称)规范,GBK1.0 收录了 21886 个汉字,是 GB2312 的 3 倍。
GBK 向下与 GB 2312
编码兼容,向上支持 ISO-10646.1
国际标准,在历史的发展中,它是一个对 GB2312 承上启下的产物。
GBK 编码,是在 GB2312-80 标准基础上的内码扩展规范,使用了双字节编码方案,共 23940 个码位,共收录了 21003 个汉字,完全兼容 GB2312 标准。他还能支持日文假名、繁体中文等字符。
GBK 也是使用 区字节+位字节的方式存储,而其高字节的从 81-FE,低字节从 40-FE,总共有 24066 个位置。
2.2.3 GB18030
GB18030 是 2000 年国家出台的取代 GBK1.0 的国标方案,用于补充 GBK 的字符,所以它是兼容 GBK 和 GB2312
它有两个大的历史版本:
GB18030-2000
2000 年的版本,收录 27533 个汉字。标准兼容 Unicode 3.0 中日韩统一表意文字
GB18030-2005
2005 年更新,收录 70244 个汉字,更新至 Unicode 3.1 中日韩统一表意文字,并收录了少数名族的文字如朝鲜族、蒙古文、藏文、维吾尔文、彝文等。
GB18030 的编码采用单字节、双字节和 4 字节方案。其中单字节、双字节和 GBK 是完全兼容的。
下面是 GB18030 的解析规则:
单字节
使用 0×00(0)至 0×7F(127)码位,与 ASCII 码对应
双字节
首字节码位从 0×81(129)至 0×FE(254),尾字节码位分别是 0×40(64)至 0×7E(126)和 0×80(128)至 0×FE(254)。和 GBK 一样(带扩展)。
四字节
四字节部分采用 GB/T 11383 未采用的 0×30(48)到 0×39(57)作为对双字节编码扩充的后缀,这样扩充的四字节编码,其范围为 0×81308130(2,167,439,664)到 0×FE39FE39(4,265,213,497)。其中第一、三个字节编码码位均为 0×81(129)至 0×FE(254),第二、四个字节编码码位均为 0×30(48)至 0×39(57)。
判断规则
从头开始读取字节,字节范围是 0~127 则是一个字节表示一个字符。
从头开始读取字节,首字节范围是 129-254,判断第二位字节;第二位字节如果是 48~57 则是四个字节表示一个字符,反之是两个字节表示一个字符。
Big5(又称大五码或五大码),它的出现时间是 90 年代,是使用繁体中文(正体中文)社区中最常用的电脑汉字字符集标准,共收录 13,060 个汉字。是由台湾那边创建的,主要使用的地区是台湾、香港、澳门这些使用繁体的区域。但它本身不是国家/地区的官方标准,只是行业标准。
Big5 码是一套双字节字符集,使用了双八码存储方法,以两个字节来安放一个字。第一个字节称为“高位字节”,第二个字节称为“低位字节”。“高位字节”使用了 0x81-0xFE,“低位字节”使用了 0x40-0x7E,及 0xA1-0xFE。百度到的分区如下:
Unicode 是由 ISO 组织来设计的,它又称万国码、统一码,第一版公布于 1994 年,设计原因是统一所有的 ASCII 扩展、ISO 字符集、各个国家的字符系统。
所以它和 GB 系列是同期的,在 90 年代,GB 系列和 Unicode 应该是在争字符集的 no.1 的,在 21 世纪之后,Unicode 更受世界各地所接受,因为它功能太过强大了,比如除了支持欧美、亚洲的字符集,还支持中亚的从右到左的书写体系,所以后期它成为了字符集的第一了。
2.4.1 Unicode
Unicode 全称为 Universal Multiple-Octet Coded Character Set,简称 USC,俗称才是 Unicode。
Unicode 和 GB、大五码不一样,它没有规定字符如何在计算机中存储,它为每种语言中的每个字符设定了统一并且唯一的二进制编码。 也就是说它是抽象,而不是实现。
上面提到,Unicode 没有规定字符对应的二进制码如何存储。以汉字“汉”为例,它的 Unicode 码点是 0xE6B189,对应的二进制数是 (111001101011000110001001),二进制数有 18 位,这也就说明了它至少需要 3 个字节来表示。可以想象,在 Unicode 字典中往后的字符可能就需要 3 个字节或者 4 个字节,甚至更多字节来表示了。
这就导致了一些问题,
计算机怎么知道你这个 2 个字节表示的是一个字符,而不是分别表示两个字符呢?
这里我们可能会想到,那就取个最大的,假如 Unicode 中最大的字符用 4 字节就可以表示了,那么我们就将所有的字符都用 4 个字节来表示,不够的就往前面补 0。
这样确实可以解决编码问题,但是却造成了空间的极大浪费,如果是一个英文文档,那文件大小就大出了 3 倍,这显然是无法接受的。
于是,为了较好的解决 Unicode 的编码问题, UTF-8 和 UTF-16 两种当前比较流行的编码方式诞生了。当然还有一个 UTF-32 的编码方式,也就是上述那种定长编码,字符统一使用 4 个字节,虽然看似方便,但是却不如另外两种编码方式使用广泛。
2.4.2 UTF-16
UTF-16 是 Unicode 的一个分支,全称 Unicode Transfer Format。16 的意思是因为最早是使用两个字节(16byte)来表示所有的字符,但是由于设计师没有考虑字符的数量庞大, 两个字节不足以表示所有字符,所以后面设计成 2 或 4 个字节表示一个字符
综上所述,UTF-16 是一种变长编码,它由 2 字节或 4 字节来表示。来看看它的编码范围:
| 字节数量 | 16 进制编码范围 | UTF-16(二进制) | 10 进制编码范围 |
| --- | --- | --- | --- |
| 2 | U+0000 - U+FFFF | xxxx xxxx xxxx xxxx - yyyy yyyy yyyy yyyy | 0~65535 |
| 4 | U+10000 - U+10FFFF | 1101 10yy yyyy yyyy - 1101 11xx xxxx xxxx | 65536-1114111 |
UTF-16 大部分的字符都是 2 字节,所以它能节省不少带宽,不过它不能兼容 ASCII 码。
2.4.3 UTF-8
UTF-8 也是 Unicode 的一个分支,它也是一种变长编码,使用 1~4 个字节来表示一个字符,因为 1 个字节的关系,所以它比起 UTF-16 可以兼容 ASCII 码。
它的判断规则为:
对于 UTF-8 编码中的任意字节 X,如果 X 的第一位为 0,则 X 独立的表示一个字符(ASCII 码)
如果 X 的第一位为 1,第二位为 0,则 X 为一个多字节字符中的后续字节(非第一字节)
如果 X 的前两位为 1,第三位为 0,则 X 为两个字节表示的字符中的第一个字节
如果 X 的前三位为 1,第四位为 0,则 X 为三个字节表示的字符中的第一个字节
如果 X 的前四位为 1,第五位为 0,则 X 为四个字节表示的字符中的第一个字节
可以看下下表:
| Unicode 十六进制码点范围 | UTF-8 二进制 | 字节数 |
| --- | --- | --- |
| 0000 0000 - 0000 007F | 0xxxxxxx | 1 |
| 0000 0080 - 0000 07FF | 110xxxxx 10xxxxxx | 2 |
| 0000 0800 - 0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx | 3 |
| 0001 0000 - 0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx | 4 |
可以看到这种编码方式还是挺独特、惊艳的。UTF-8 一般不用于计算机硬件编码,更多的是用于网络的数据交换,我们使用 Http 的传输,使用的数据格式都会支持 UTF-8/UTF-16 的。
2.4.4 UTF-32
UTF-32 是四字节的定长编码,是最为简单的编码方案,所以它没有上述复杂的判断规则,直接取偏移值查表就行了,即 O(1)的时间复杂度,但是同时带宽消耗会挺大了,就是时间换空间这样。
2.1-2.4 的编码都是字符集为主。除此之外,Base 系列也是一种常见的编码格式。
2.5.1 Base64
Base64 的原理是将二进制数据(非文本数据)转换成由 64 个字符组成的字符串的编码算法。
64 个字符是 a-z A-Z 0-9 + / 组成的字符,有一个专门的码表:
比如 M 的 ASCII 是 77,对应的二进制是 01001101。
然后自己规定,每 6 位截取一下,那么就能 切成 010011 + 01,其中 前半部分换成 10 进制是 19,在码表中对应 T,后半部分 01 换成十进制是 1,在码表中对应 B。
那么 M 被 Base64 转换之后就变成了 TB。
其中最多只能规定 6 位截取一下,因为码表只有 64 个字符,如果超出 6 位,那么多出来的码表就没有了。
Base64 的优点是简单。
评论