字符编码

先说两个基础知识。

(1)计算机内部,数据是由0,1组成的;

(2)计算机最小的数据单位,就是一个二进制单位即bit,接下来就是8个二进制单位表示一个字节(Byte)。

1 ASCII码

ASCII码(American Standard Code for Information Interchange,美国信息交换标准)只能用0,1表示26个字母(大小写共计52个),阿拉伯数据(10个),还有一些标点符号、运算符号以及控制符(如换行,回车等)。

如果需要非常清楚的知道对应规则,可以查阅ASCII码表

需要表示的不多,所以仅拿出7位数字(0-127)来表示字符,这叫做基础ASCII码。剩下的(128-255)则留作扩展用。这也就意味着基础ASCII码字节的最高位永远是0

在Python里可以看一下。

print('a') #打印字母a
print(ord('a')) #打印出字母a的ASCII码十进制
print(bin(ord('a'))) #打印出字母a的ASCII码二进制

输出结果

a
97
0b110 0001  #0b表示是二进制,最高位是0,但python输出自动省略了

2 多字节字符编码(MBCS)——以中文为例

表示汉字的话,ASCII码就不够用了,那么就拿多个字节来表示。不同国家语言文字的编码都要遵守一个共同的法则,就是要对ASCII码保持向下兼容。

也就是,最核心的就是原来ASCII码最高位为0,那么如果仍然是英文字母,这个最高位就还是0,而不是英文字母,这个最高位就变成1。

2.1 GB2312

以我们中文而论,我们国家在 1981 年发布了简体中文汉字编码国家标准,也称为 GB2312。

它的大致思想是使用1个94*94 的矩阵将所有字符存储起来。行称为区,列成为位。而中文字符也按照常用程度分为一级汉字和二级汉字。每一个中文字符都是用区字节和位字节来表示的。为了和 ASCII 码兼容,作了如下规定:一个小于 127 字符的意义与原来ASCII 码相同,但两个大于 127 的字符连在一起就表示的是一个汉字。一个汉字。这样实际上就足够有214 = 16384种表示方法,这个数字不仅能够涵盖绝大部分的中文简体字,还可以把数学符号,罗马希腊字母以及日本的假名都编进去,甚至原来在ASCII 码里的数字、标点和字母也编了进去。但是这些数字和字母和原来 ASCII 码不同的是它是用两个字节表示的,因此称作全角符号,而原来的 ASCII 码字符则还称作半角符号。


GB2312编码对所收录字符进行了“分区”处理,共94个区,每区含有94个位,共8836个码位。这种表示方式也称为区位码。
01-09区收录除汉字外的682个字符。
10-15区为空白区,没有使用。
16-55区收录3755个一级汉字,按拼音排序。
56-87区收录3008个二级汉字,按部首/笔画排序。
88-94区为空白区,没有使用。
举例来说,“啊”字是GB2312编码中的第一个汉字,它位于16区的01位,所以它的区位码就是1601。

具体的可以参看这个网站GB2312编码


但由于要和 ASCII 码兼容,无论区码还是位码都要最高位为1。理论上我们只需要将每个码加上128(十六进制表示0x80),但是GB2312规定的是每个码加上160(十六进制表示0xa0)。这样“啊”在计算机里真正的存储为0xb0,0xa1。

2.2 GBK

但是GB2312实际上只收录了6763 个汉字,对于绝大部分应用是够了。但是对于特殊字就不好办了。还有就是台湾人民所使用的繁体字(big5编码),也不支持。

原来 GB2312 规定两个字节最高位都不能是1,而 GBK 规定首字节的最高位为1,我们就认为后面是两个字节来表示汉字,而第2个字节的最高位可以不是1。于是乎就大大扩展了编码范围,这一次收录了21003个汉字,而且将繁体字也纳入进来。

2.3 BIG5

1984年,台湾五大厂商宏碁、神通、佳佳、零壹以及大众一同制定了一种繁体中文编码方案,因其来源被称为五大码,英文写作Big5,后来按英文翻译回汉字后,普遍被称为大五码。目前,Big5编码在台湾、香港、澳门及其他海外华人中普遍使用,成为了繁体中文编码的事实标准。由于Big5编码和GB2312编码是冲突的,因此一个文本内不可能既支持BIG5,也支持GB2312。实际上虽然GBK可以支持繁体中文,但是它和BIG5编码也是相互冲突,并不兼容的。

2.4 CodePage, MBCS, DBCS和ANSI

不仅仅中文如此,日文、韩文以及其他国家的文字也都是如此。因此这一类我们称之为多字节字符编码(MBCS),但是由于实际上都是两个字节,因此有的时候我们也将其称之为双字节字符编码(DBCS)。微软也将其称之为美国国家标准(ANSI),所以我们在使用操作windows系统的记事本的时候,在另存时选择字符编码为ANSI,如果你是简体中文操作系统,其实就是GBK,而如果是繁体操作系统的话,则是BIG5编码。IBM为了统一各国字符编码系统,他把所有的编码编成了一本厚厚的“书”,中文的GBK编码在936页,因此也称之为CodePage-936,而BIG5在950页,也称之为CodePage-950。

CodePage,MBCS,DBCS和ANSI这四个概念,其实是同一个意思,它们均不特指某一个字符编码,而是在不同的地区和国家包括特定的含义。

3 统一字符编码(Unicode, UTF-8)

最早的Unicode编码是通过两个字节来进行编码,但是我们已经知道两个字节最多只能有\(2^{16}=65,536\)种表示方法,这个用来表示基于字母的语言是够用的,但是对于类似中文、韩文、日文这样的文字,那么这个编码还不够。于是Unicode拿出了四个字节来进行存储。第1个字节称之为组,第2个字节称之为面,第3个字节称之为行,第4个字节称之为点。其中第0组,第0个面,会涵盖绝大部分我们所使用的文字,因此也称之为基本多语种平面(Basic Multilingual Plane)。

实际上,我们现在仅用了17个平面(从平面0-平面16)来存储全世界所有的文字,这样实际上是总共用了\(65,536×17=1114112\)个码位。也就是说全世界所有的文字都能够在0-1114111当中找到,这里面包括了71226个汉字。

规定了这所有文字的编码后,接下来面临的一个问题就是如何将这些文字编码以字节的形式表示在计算机里,这个过程我们也称之为Encoding过程。

于是出现了各种编码转换方法(Universal Transformation Formats),而最为著名的就是UTF-8。这个也促成了Unicode编码和计算机存储的分离。UTF-8的编码原则有以下2条:

  • 如果一个字符的Unicode编码小于128,这用一个字节表示,保证了兼容ASCII码;

  • 如果一个字符大于128,这按照如下表规则编码成2、3或者4个字节。

【参考】

[1]《爬虫基础知识之字符编码(以Python为例)》互联网空间数据挖掘研究小组

[2] GB2312编码表

posted @ 2018-12-08 15:31  Yingjing  阅读(459)  评论(0编辑  收藏  举报