文档章节

字符集与编码(九)——GB2312,GBK,GB18030

国栋
 国栋
发布于 2014/12/05 17:04
字数 3249
阅读 2416
收藏 60
点赞 8
评论 4

前面的一些篇章更多谈论了Unicode的相关话题,虽然也有提到GBK等编码,但都没细说,这里打算系统说一下。GB系列包括GB2312,GBK,GB18030.

前面已经提过,GB=Guo Biao=国标=国家标准,至于所谓的2312就是一编号了,没有其它特别的意义,18030类似。GBK没有编号,所以它实际上并不是国家标准,只是一个事实标准,GBK中K指“扩展”的意思。

最早的是GB2312,我们从它开始说起。

GB2312


以下为一简介(官方文档见"国家标准化管理委员会"网站:http://gbread.sac.gov.cn/bzzyReadWebApp/standardresources.action?m=readFile&bzNum=GB%202312-1980&flag=1,用IE打开,它要安装一个ActiveX插件):

GB 2312-1980,全称《信息交换用汉字编码字符集 基本集》,由国家标准总局于1980年3月9号发布,1981年5月1日实施,通行于大陆。新加坡等地也使用此编码。它是一个简化字的编码规范,也包括其他的符号、字母、日文假名等,共7445个图形字符,其中汉字占6763个。

上述官网地址无法下载,如果你想下载,可试下这个ftp://ftp.oreilly.com/examples/cjkvinfo/AppE/gb2312.pdf(比标准方案多增加了一些字符)

作为一个编码字符集而言,前面也曾说到,它采用了所谓的二维区位编号,下面是一个概览图:

image

它是一个94×94的表格,理论上有94×94=8836个空间。

横的叫区,竖的叫位,总共94个区,区和位的编号都从1开始。可以看到粗略有三大部分。

94个区

1. 中间黑色的主体部分即是汉字区了,具体为16-87区,共87-16+1=72个区,理论空间为72×94=6768.

从上图中可以看到中间有5个编码为空白(中间靠右边部分,55区最后5个位),所以总共有6768-5=6763个汉字。

一级汉字与二级汉字:

image

第16-55区:一级汉字,3755个(以拼音字母排序)
第56-87区:二级汉字,3008个(以部首笔画排序)

2. 最下面的88-94区是有待进一步标准化的空白区。

3. 关于前面的01-15区,下图为概览图左上角的局部放大图:

image

1. 01-09区为符号、字母、日文假名等,部分区还有空白位。

03区即是对应ASCII字符的全角字符区。输入法的全角模式下输入的即是这些字符。

2. 10-15区也是有待进一步标准化的空白区。

各区的一个具体情况:

第01区:中文标点、数学符号以及一些特殊字符
第02区:序号
第03区:全角西文字符
第04区:日文平假名
第05区:日文片假名
第06区:希腊字母表
第07区:俄文字母表
第08区:中文拼音字母表
第09区:制表符号 
第10-15区:未定义
第16-55区:一级汉字(以拼音字母排序)
第56-87区:二级汉字(以部首笔画排序)
第88-94区:未定义

区位码

在上图中还标出了一个汉字“啊”,它就是GB2312方案中的天字第一号汉字,它处于16区01位上,所以它的区位码即是1601.

所谓区位码就是这一94×94的大表格中的行号与列号了,均从1开始编号。

第一个字符0101为“全角空格”(图中显示为SP(space))。

国标码

将区位码的区和位分别加上32(=0x20)就得到了国标码。

“啊”的区位码是16-01,分别加32,得到16+32-01+32=48-33,即是国标码。当然,你通常应该写成16进制,48-33即是0x30-0x21,所以3021即是“啊”十六进制的国标码,使用两字节保存,30为高字节,21为低字节。如下:

image

GB2312方案规定,对上述表中任意一个图形字符都采用两个字节表示,每个字节均采用七位编码表示。

如上图所示,只用了7位,这即是说最高位就是0了。

但为何不直接采用区位码呢?为什么要加32呢?你也许还记得前面说到ASCII时,前面32个字符是控制码,中文系统自然也不能少了这些控制码,为了不与这些控制码冲突,加上32就能跳过它们了。

一字节有128个空间,128-32=96,实际上,ASCII中第127个也是控制码(DEL, 删除),再减去就还有95个有效位,再加上区位从1开始,又损失了一位,所以最终只有94个有效位了,这也是前面为何是一个94×94的表格。

国标码的定位实际应该是与ASCII一致的,是作为国家信息交换的标准码。从设计上看,它并没打算兼容ASCII,它已经把ASCII中的字符收录了过来,不过是作为所谓的全角字符来看待,但全角英文显示效果其实是很差的,下面是全角英文的一个示例:

hello,world

显得非常不紧凑,最终,一种能兼容ASCII的存储方案得到了广泛采纳,这就是所谓的机内码了。

机内码

将国标码高低字节分别加上0x80(=128)就得到了机内码(有时又叫交换码)。128的二进制形式为10000000,加128,简单地讲,就是把国标码最高位置成1.至于为什么要这样呢?我想你应该也清楚了,就是要兼容ASCII,ASCII最高位为0,国标码加128后,高低字节的最高位都成了1,这样就与ASCII区分开来。

将“啊”的国标码3021分别加上0x80,0x30+0x80=0xB0,0x21+0x80=0xA1,所以B0A1即是机内码。

如果从区位码算起,那么则是加上0x20+0x80=32+128=160=0xA0,也即区位码的区和位分别直接加上0xA0即可得到机内码,如下图所示:

image

如果你新建一个文本文件,录入“啊”字,以GB2312编码方式保存(使用GBK即可,它兼容GB2312),再用十六进制查看,你会发现使用的是机内码:

image

使用代码的测试也可验证这一点:

    @Test
    public void testAh() throws UnsupportedEncodingException {
        String ah = "啊";
        assertThat(DatatypeConverter.printHexBinary(ah.getBytes("GB2312"))).isEqualTo("B0A1");
    }

虽然我们常把GB2312称为国标码,但我们应该清楚,实际存储使用的是机内码,通常说到GB2312编码时指的就是这个机内码了。它能兼容ASCII,是一种变长的编码方案,对ASCII中的字符(也即所谓的“半角西文字符”)采用一字节编码,最高位为0;对区位表中的字符采用两字节编码,且每字节最高位均为1,以此区分。

自然,全角英文字符就是两字节编码了,跟汉字是一样的。

下面是一个混合了汉字,半角字母a和全角字母a的编码示例,共5个字节:

image

我们说GB2312是一个变长编码方案,是站在其兼容ASCII编码角度而言,就其方案标准本身定义的字符而言,它是一个双字节定长编码方案。

你可能会想,那国标码还有什么用?

我个人觉得,国标码既然称为中文信息交换的标准码,必然要成为“机内”码才有意义,只不过由于各种原因,最终未能如愿。早期的一些系统或者一些小型的嵌入式系统或许采纳了它做为“机内”码。当然以上为个人猜测,仅供参考。

另:我在前面的一些文章中谈到区位码时把它与机内码混为一谈,特此更正。

下面是三种码在256×256坐标中的位置的一个示意图:

image

GBK


GBK是对GB2312的一个扩展,兼容GB2312,因此也兼容ASCII,也是一个变长编码方案。下面是一个简介:

GBK总体编码范围为8140-FEFE,首字节在81-FE 之间,尾字节在40-FE 之间,总计23940 个码位,共收入21886个汉字和图形符号,其中汉字(包括部首和构件)21003 个,图形符号883 个。

GBK是国家有关部门与一些信息行业企业等一起合作推出的方案,但并未作为国家标准发布,只是一个事实上的标准,一个过渡方案,为GB18030标准作的一个准备。

首字节(lead byte)

下面是Windows Code page: 936 (GBK),第一字节的概况(来自http://msdn.microsoft.com/en-US/goglobal/cc305153.aspx

image

Code page 936实质上是GBK到UTF-16编码的一个转换表,图中字符下面标注的四位16进制数字即是UTF-16编码

1. 上面部分是兼容ASCII单字节编码。

2. 下面阴影部分是双字节编码中的第一个字节,表中作为超链接,可以点击进去查看具体内容。

注:0x80(=128)被用于欧元符。(图中小圆框部分)0xFF则保留,实际共有128-2=126块。

另:新的GB18030标准使用双字节编码欧元符号,去掉了这个单字节编码。

第二字节

前面说到“啊”的机内码是B0A1,我们点击B0(上图中红色小框部分)去查看一下(来自http://msdn.microsoft.com/en-US/goglobal/gg675356):

image

1. “啊”位于A1处,所以它是兼容GB2312的。而前面的那些字符就是GBK扩展的了。

“啊”下面的554A即是它的UTF-16编码。GBK与UTF-16之间编码的转换只能通过查表实现。

2. 第二字节从0x40开始,不是从0x00也不是从0x80开始。表格只有12行。

因为不是从0x80开始,这意味着第二字节最高位也可能是0.这点与GB2312不同,GB2312确保了无论是高低字节最高位均是1。

3. 另外0x7F和0xFF两处保留未定义。

所以实际有12×16-2=192-2=190个字符。注:并非所有的块里面都是190个字符,也有不少是少于190的。

粗略估算可得126×190=23940,所以GBK也就是两万多个字符这样子。

GBK还是UTF-8?

GBK使用两字节保存中文,也能兼容ASCII,而对常用汉字,UTF-8都是采用三字节编码,因此无论是全中文还是中英文混合的情况,GBK保存的效率都要好于UTF-8.

这也不奇怪,毕竟是亲生的。

但它也有些不好的地方,比如它不能支持一些国际性的文字,在国际化,通用性方面它肯定不如UTF-8;就汉字而言,由于容量空间的限制,它也无法收录更多的汉字了。

所以,怎么选择,自己看着办。

GB18030


GB18030前后发布了两个标准,最新的是2005年发布的GB 18030-2005(《信息技术 中文编码字符集》),2000年还有一版GB18030-2000,更多了解可参考百度百科http://baike.baidu.com/view/889058.htm,官网见http://gbread.sac.gov.cn/bzzyReadWebApp/standardresources.action?m=readFile&bzNum=GB 18030-2005&flag=1,(注:这个文件比较大)

对于多数用户而言,无需了解太多,这里也不打算详细介绍,下面是一些简介(针对最新的GB18030-2005):

  1. 它也是一个多字节编码方案,有一,二,四字节三种变长组合。

  2. 它的编码空间很大,高达160万(约数),这甚至超过了Unicode规定的110万(约数)。

  3. 它兼容GB2312,基本兼容GBK(只有很少几处不同)。

  4. 它收录高达7万多的汉字,Unicode中的CJK统一汉字,CJK统一汉字扩充A,CJK统一汉字扩充B均收录了进来。

  5. 它还支持许多少数民族如藏、蒙古、彝、维吾尔等的文字。

对于普通用户,超大字符集很少用到,通常情况下,如Windows系统下你可能要安装GB18030的相关插件才能处理及显示那些增补的字符,一般系统默认情况也不会安装能支持完整显示GB18030全体字符的字体。

GB18030作为一个强制标准,但由于采用了高达四字节的情形,无论是操作系统还是各种应用软件,可能涉及许多调整才能很好地支持,这决不是一件简单的事情。

作为国际性标准的Unicode,BMP以外的字符的处理与显示都还有很多不完善,所以如果GB18030没有得到很好的支持,那也不足为奇了。

关于GB系列的编码就说到这里。

© 著作权归作者所有

共有 人打赏支持
国栋

国栋

粉丝 362
博文 78
码字总数 154046
作品 0
东莞
程序员
加载中

评论(4)

开源中国七里香
开源中国七里香
把这个系列看完了,很有收获呀
小拐
小拐
多谢博主8379
雾渺
雾渺
非常详尽
n
newnoder
好文,赞
HTML,CSS,font-family:中文字体的英文名称

HTML,CSS,font-family:中文字体的英文名称 宋体 SimSun 黑体 SimHei 微软雅黑 Microsoft YaHei 微软正黑体 Microsoft JhengHei 新宋体 NSimSun 新细明体 PMingLiU 细明体 MingLiU 标楷体 ...

潜心笃志 ⋅ 03/23 ⋅ 0

HTML,CSS,font-family:中文字体的英文名称 (宋体 微软雅黑)

宋体 SimSun 黑体 SimHei 微软雅黑 Microsoft YaHei 微软正黑体 Microsoft JhengHei 新宋体 NSimSun 新细明体 PMingLiU 细明体 MingLiU 标楷体 DFKai-SB 仿宋 FangSong 楷体 KaiTi 仿宋GB231...

h2appy ⋅ 2017/05/16 ⋅ 0

中文字体的英文名称

宋体 SimSun 黑体 SimHei 微软雅黑 Microsoft YaHei 微软正黑体 Microsoft JhengHei 新宋体 NSimSun 新细明体 PMingLiU 细明体 MingLiU 标楷体 DFKai-SB 仿宋 FangSong 楷体 KaiTi 仿宋GB231...

赤月三号 ⋅ 2016/08/10 ⋅ 0

CSS,font-family,好看常用的中文字体

写在前面:继续完善自己的简历,想要找找比较好看的字体,看到了一篇博客直接拿来用 例1(小米米官网):font-family: "Arial","Microsoft YaHei","黑体","宋体",sans-serif; 例2(淘宝技术研...

红羊在北京 ⋅ 2016/08/25 ⋅ 0

常见字符集

常见字符集 我们都知道中文是世界上文字符号最多的国家,中国的文字符号超过了非中文国家文字符号的总和,中华文明渊源流长啊! 中文的字符集也是最复杂的字符集,为了向后兼容,设计中文字符...

耿中华 ⋅ 2014/09/02 ⋅ 0

让人抓狂的编码问题

通过get方式提交的数据,需要在tomcat的server.xml文件里设置URLEncoding =”utf-8”配置。 通过post方式提交的数据,需要在request.getParameter()之前,调用request.setCharacterEncoding(...

安国庆 ⋅ 2013/11/20 ⋅ 0

关于字符集和字符编码的问题

在系统管理或一些软件管理中,总是碰到需要设置字符集或字符编码的地方,如果设置不正确,可能产生许多意想不到的问题。 但是在具体概念上,不仅自己,网络上也有很多人不太理解“字符集”和...

wuwei5460 ⋅ 2014/02/24 ⋅ 0

配置源码安装的MySQL同时支持多个字符集

################################################################ 系统环境:RHEL5 [ 2.6.18-8.el5xen ] 软件环境: httpd-2.2.8 mysql-5.0.22 php-5.2.6 这里仅提供编译安装mysql、httpd......

心心 ⋅ 2012/12/27 ⋅ 0

Locale: 字符集(character set).

char 可被应用于所有8bit以及8bit以下的字符集,例如: US-ASCII,ISO-Latin-1和ISO-Latin-9以及UTF-8. char16_t 可被用于UCS-2,也可被用于UTF-16的code unit(代码单元). char32_t 可被用于U...

SHIHUAMarryMe ⋅ 2016/09/25 ⋅ 0

字符集和字符编码

字符集和字符编码[订正] 这个主题已经被N多人讨论过了,这里仅仅是个人总结,不是教程。 字符集和字符编码 潘孙友 2010-12-31 于遵义 目录一、字符集二、字符编码三、Windows平台3.1 Codepag...

zungyiu ⋅ 2011/01/07 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

JVM堆的理解

在JVM中,我们经常提到的就是堆了,堆确实很重要,其实,除了堆之外,还有几个重要的模块,看下图: 大 多数情况下,我们并不需要关心JVM的底层,但是如果了解它的话,对于我们系统调优是非常...

不羁之后 ⋅ 昨天 ⋅ 0

推荐:并发情况下:Java HashMap 形成死循环的原因

在淘宝内网里看到同事发了贴说了一个CPU被100%的线上故障,并且这个事发生了很多次,原因是在Java语言在并发情况下使用HashMap造成Race Condition,从而导致死循环。这个事情我4、5年前也经历...

码代码的小司机 ⋅ 昨天 ⋅ 1

聊聊spring cloud gateway的RetryGatewayFilter

序 本文主要研究一下spring cloud gateway的RetryGatewayFilter GatewayAutoConfiguration spring-cloud-gateway-core-2.0.0.RC2-sources.jar!/org/springframework/cloud/gateway/config/G......

go4it ⋅ 昨天 ⋅ 0

创建新用户和授予MySQL中的权限教程

导读 MySQL是一个开源数据库管理软件,可帮助用户存储,组织和以后检索数据。 它有多种选项来授予特定用户在表和数据库中的细微的权限 - 本教程将简要介绍一些选项。 如何创建新用户 在MySQL...

问题终结者 ⋅ 昨天 ⋅ 0

android -------- 颜色的半透明效果配置

最近有朋友问我 Android 背景颜色的半透明效果配置,我网上看资料,总结了一下, 开发中也是常常遇到的,所以来写篇博客 常用的颜色值格式有: RGB ARGB RRGGBB AARRGGBB 这4种 透明度 透明度...

切切歆语 ⋅ 昨天 ⋅ 0

CentOS开机启动subversion

建立自启动脚本: vim /etc/init.d/subversion 输入如下内容: #!/bin/bash## subversion startup script for the server## chkconfig: 2345 90 10# description: start the subve......

随风而飘 ⋅ 昨天 ⋅ 0

Nginx + uwsgi @ubuntu

uwsgi 安装 sudo apt-get install python3-pip # 注意 ubuntu python3默认没有安装pippython3 -m pip install uwsgi 代码(test.py) def application(env, start_response): start_res......

袁祾 ⋅ 昨天 ⋅ 0

版本控制工具

CSV , SVN , GIT ,VSS

颖伙虫 ⋅ 昨天 ⋅ 0

【2018.06.19学习笔记】【linux高级知识 13.1-13.3】

13.1 设置更改root密码 13.2 连接mysql 13.3 mysql常用命令

lgsxp ⋅ 昨天 ⋅ 0

LVM

LVM: 硬盘划分分区成物理卷->物理卷组成卷组->卷组划分逻辑分区。 1.磁盘分区: fdisk /dev/sdb 划分几个主分区 输入t更改每个分区类型为8e(LVM) 使用partprobe生成分区的文件:如/dev/sd...

ZHENG-JY ⋅ 昨天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部