汉字是如何编码的

本文我们简单聊聊汉字编码方案,例如 GB2312。

GB2312 的字符集

字符编码,是对字符进行的编码,那么首先得有一个字符集,然后再去编码,就像 ASCII 码也是对 ASCII 字符集进行的编码。

那中国的字符集怎么设定呢?以 GB2312 为例,国家标准局用了分区管理的方式,将公布的 6763 个两级汉字分为 94 个区,每个区 94 位,实际上就是把汉字表示成二维数组,每个汉字在数组中的下标就是区位码(表示其属于哪个区、哪个位)。区码和位码各是两位十进制数,因此一个汉字是 4 个十进制数,例如“中”字位于第 54 区 48 位,区位码位 5448

为什么使用分区

为什么要分区来管理呢?ASCII 编码方案多简单,不好吗?目前并未搜到为何这么设计,个人认为分区是为了方便管理。中国的汉字特别多,就好比学校中,由于学生太多,因此采用了分班管理的方式,每个班再给学生编号,这样比较好管理

感兴趣的同学,可以去国家标准网上查看 GB2312 的文档,国家标准 |GB/T 2312-1980,可以在线预览文档(没找到下载按钮,无法预览)

文档在线预览地址:在线预览 |GB/T 2312-1980, 部分内容:

区位码简单说明

我们继续来讲 GB2312 的区位码设计。在 94 个区中:

  • 01 ~ 09 区:收录了除汉字外的 682 个字符
  • 10 ~ 15 区:空白区,没有使用
  • 16 ~ 55 区:收录了 3755 个一级汉字,按拼音排序
  • 56 ~ 87 区:收录了 3008 个二级汉字,按部首/笔画排序,不太常用,生僻的一些汉字。
  • 88 ~ 94 区:空白区

我们简单看看 01 ~ 09 区的字符:

图片来自非常详细的字符编码讲解,ASCII、GB2312、GBK、Unicode、UTF-8 等知识点都有_哔哩哔哩

第 16 ~ 55 区的截图如下。前面我们说过 “中”字位于第 54 区 48 位,区位码位 5448。读者也可以去看 在线预览 |GB/T 2312-1980 第 22 页:

56 ~ 87 区的部分截图如下:

GB2312 如何存储

我们之前只讲了区位码,但没有规定怎么在计算机里存储。我们以侃字为例,侃的区位码是 5709,我们将区和位分开,并转为 16 进制。57 对应 0x39, 09 对应的还是 0x09。然后将区码和位码分别加上 A0,得到 0xD9 和 0xA9,然后合并,就是 0xD90xA9:

为什么要加 A0:为了兼容 ASCII。GB2312 是双字节编码,为了与 ASCII 码区分开,字节的第 8 位必须是 1,所以至少要从 0x80(128, 1000 0000) 开始,但是根据上面的规定,0x80 - 0x9f 要留给控制块,所以只能从 0xA0 开始。那为什么 GB2312 编码不是从 0xA0 开始,而是 0xA1 开始呢? 因为 0xA0 正好是图形块的空格,所以就从 0xA1 编码,这就是 0xA0 的由来。

综上,一个汉字要占两个字节,两个字节均大于 127。

实践:查看汉字的 GB2312 码

如果你用过 Python,可以用以下代码打印出侃的 GB2312 码

print('侃'.encode('gb2312')) # 结果为'\xd9\xa9'

读者也可以新建一个 txt 文件,然后通过 IDE 或者编辑器的十六进制的方式查看文件,以 Sublime 为例:

这里不展开,有兴趣的读者请自行上网搜索。

如果你在 Linux 下,可以使用 hexdump 命令:

$hexdump  侃.txt
0000000 a9d9   

GBK

因此,在 1995 年,中国发布了 GBK 编码,其包含了 GB2312 的所有内容,同时新增了近 20000 个新的汉字(繁体字)和符号

GBK 编码不再要求低字节要大于 127,只要第一个字节大于 127 就表示是一个汉字的开始。

posted @ 2024-06-16 10:53  peterjxl  阅读(28)  评论(0编辑  收藏  举报