GB2312、GBK、GB18030等GB系列汉字编码方案的具体实现方式是怎样的?区位码是什么?国标码是什么?内码、外码、字形码又是什么意思?它们是如何转换的,又为什么要这样转换?

下面以GB2312为例来加以说明。

一、区位码

1.

整个GB2312字符集分成94个区,每区有94个位,每个区位上只有一个字符,即每区含有94个汉字或符号,用所在的区和位来对字符进行编码(实际上就是码点值、码点编号、字符编号),因此称为区位码(或许叫“区位号”更为恰当)。

换言之,GB2312将包括汉字在内的所有字符编入一个94*94的二维表,行就是“区”、列就是“位”,每个字符由区、位唯一定位,其对应的区、位编号合并就是区位码。

比如“万”字在45区82位,所以“万”字的区位码是:45 82(注意,GB类汉字编码为双字节编码,因此,45相当于高位字节,82相当于低位字节)。

2.

GB2312字符集中:

1)01~09区(682个):特殊符号、数字、英文字符、制表符等,包括拉丁字母、希腊字母、日文平假名及片假名字母、俄语西里尔字母等在内的682个全角字符;

2)10~15区:空区,留待扩展;

3)16~55区(3755个):常用汉字(也称一级汉字),按拼音排序;

4)56~87区(3008个):非常用汉字(也称二级汉字),按部首/笔画排序;

5)88~94区:空区,留待扩展。

二、国标码(交换码)

1.

为了避开ASCII字符中的不可显示字符0000 0000 ~ 0001 1111(十六进制为0 ~ 1F,十进制为0 ~ 31)及空格字符0010 0000(十六进制为20,十进制为32)(至于为什么要避开、又为什么只避开ASCII中0~32的不可显示字符和空格字符,后文有解释),国标码(又称为交换码)规定表示汉字的范围为(0010 0001,0010 0001) ~ (0111 1110,0111 1110),十六进制为(21,21) ~ (7E,7E),十进制为(33,33) ~ (126,126)。

因此,必须将“区码”和“位码”分别加上32(十六进制为20,可写作20H或0x20,后缀H或前缀0x都可表示十六进制),作为国标码。也就是说,国标码相当于将区位码向后偏移了32,以避免与ASCII字符中0~32的不可显示字符和空格字符相冲突。

2.

注意,国标码中是分别将区位码中的“区”和“位”各自加上32(20H)的,因为GB2312是DBCS双字节字符集,因此国标码属于双字节码。

这样我们可以算出“万”字的国标码十进制为:(45+32,82+32) = (77,114),十六进制为:(4D,72),二进制为:(0100 1101,0111 0010)。

(笨笨阿林原创文章,转载请注明出处)

三、内码(机内码)

1.

不过国标码还不能直接在计算机上使用,因为这样还是会和早已通用的ASCII码冲突,从而导致乱码。

比如,“万”字国标码中的高位字节77与ASCII的“M”冲突,低位字节114与ASCII的“r”冲突。因此,为避免与ASCII码冲突,规定国标码中的每个字节的最高位都从0换成1,即相当于每个字节都再加上128(十六进制为80,即80H;二进制为1000 0000),从而得到国标码的“机内码”表示,简称“内码”。

2.

由于ASCII码只用了一个字节中的低7位,所以,这个首位(最高位)上的“1”就可以作为识别汉字编码的标志,计算机在处理到首位是“1”的编码时就把它理解为汉字,在处理到首位是“0”的编码时就把它理解为ASCII字符。

比如:

  77 + 128 = 205(二进制为1100 1101,十六进制为CD)

  114+ 128 = 242(二进制为1111 0010,十六进制为F2)

3.

我们可以来检验一下。打开记事本输入“万”字,编码选择为ANSI(Windows记事本中的ANSI编码在简体中文版操作系统中默认为GB类编码,详见后文解释),保存,如下图所示。

然后用二进制编辑器(比如UltraEdit)打开刚才保存的文件,切换到十六进制模式,会看到:CD F2,这就是“万”字的内码,如下图所示。

4.

小结一下:

从区位码(国家标准定义) ---> 区码和位码分别+32(即+20H)得到国标码 ---> 再分别+128(即+80H)得到机内码(与ACSII码不再冲突)。

因此,区位码的区和位分别+160(即+A0H,32+128=160)可直接得到内码。用十六进制表示就是:

   区位码(区码, 位码) + (20H, 20H) + (80H, 80H)
  = 区位码(区码, 位码) + (A0H, A0H)
  = 内码(高字节, 低字节)。

(注:十六进制数既可通过添加后缀H来表示,也可通过添加前缀0x来表示)

四、为什么要加上20H和80H?

1.

区位码、国标码、内码的转换非常简单,但令人迷惑的是为什么要这么转换?

首先,需要注意到一点,GB2312虽说是汉字编码方案,但其实里面也有针对26个英文字母和一些特殊符号的编码,按理说这些和ASCII重合的字符(33~127)应该无需再重新编码,直接沿用ASCII编码不就行了?

2.

原来,当时在制定GB2312时,决定对ASCII中的可打印字符,也就是英文字母、数字和符号部分(33~126,127为不可打印的DEL)重新编入GB2312中,以两个字节表示,称之为全角字符(全角字符在屏幕上的显示宽度为ASCII字符的两倍,后来也因此而将对应的ASCII字符称之为半角字符)。

而对于ASCII中前32个不可显示也不可打印的控制字符(ASCII码为0~31),以及第33个可显示但不可打印的空格字符(ASCII码为32)等一共33个不可打印字符的编码则直接沿用,不再重新编码。

3.

因为要保留这33个不可打印字符,就不能直接采用区位码作为计算机直接处理的机内码,需要将区位码向后偏移32以避开冲突(为什么是偏移32,而不是偏移33?因为区位码中的区码和位码都是从1开始计数的,不像ASCII码是从0开始计数的)。

十进制数字32的十六进制表示就是20H,这也就是区位码的区码和位码都分别要加上20H才能得到国标码的原因。

(笨笨阿林原创文章,转载请注明出处)

4.

不过,如果直接采用国标码作为计算机直接处理的机内码的话,还是会与ASCII编码产生冲突,导致乱码。

因为国标码虽然相较于区位码避开了ASCII码中0~32的前33个不可打印字符,但并没有避开ASCII码中的英文字母、数字和符号等可打印字符(33~126,共94个字符)以及不可打印的DEL(127)。也就是说,国标码并不是完全兼容ASCII码的。

5.

为了彻底避免与ASCII码的冲突,考虑到ASCII码只使用了一个字节中的低7位,其最高位(即首位)总是为0,于是决定将国标码中每个字节的最高位设为1(国标码的两个字节中的最高位都总是为0,即国标码中的每个字节与ASCII码一样实际上也只用了一个字节中的低7位),这就是GB2312的机内码(即内码),简称GB2312码。

这样一来就彻底区分开了ASCII码和GB2312码。这也是为什么国标码还要加上(80H,80H)才能得到机内码的原因。

6.

看到这里,有人或许又要问了:如果仅仅是为了避免与ASCII码相冲突,为什么最初不直接将区位码的区码和位码的最高位从0改为1(相当于各自直接加上128),这样不就无需经过国标码多此一举的中间转换了吗?而且还无需后移32,也就不用浪费这部分编码空间。

对此本人也很困惑,在网上搜了很久也没找到答案,因此具体原因不得而知。或许是一开始考虑不周?或许是为了未来扩展所需而预留一部分空间?又或许是有其他不得已的原因?有知道的朋友还望能指点迷津。

GB2312区位码、国标码、内码对照表(其中汉字内码B0A1~F7FE,共6763个)

五、外码(输入码、输入法编码)

1.

外码也叫输入码、输入法编码,是用来将汉字输入到计算机中的一组键盘符号,是作为汉字输入用的编码。

英文字母只有26个,可以把所有的字符都放到键盘上,而使用这种办法把所有的汉字都放到键盘上是不可能的。所以汉字系统需要有自己的输入码体系,使汉字与键盘能建立起对应关系。

2.

目前常用的汉字外码分为以下几类:

1)数字编码,比如区位码;

2)拼音编码,比如全拼、双拼、自然码等;

3)字形编码,比如五笔、表形码、郑码等。

3.

汉字外码往往会出现重码。

所谓重码,指的是同一个汉字外码对应于多个汉字,反过来说,也就是可能有多个汉字的外码是相同的,相当于重复了,所以称之为“重码”。比如使用拼音作为外码时(即使用拼音输入法输入汉字时),重码现象是相当普遍的。

当出现重码时,往往需要附加选择编号以具体确定所要输入的汉字,这种情况下,可认为外码实际上相当于隐式地包括了选择编号在内。

六、字形码(字型码、字模码、输出码)

1.

字形码,又称为字型码、字模码、输出码,属于点阵代码的一种。

为了将汉字在显示器或打印机上输出,把汉字按图形符号设计成点阵图,就得到了相应的点阵代码(字形码)。

也就是用0、1表示汉字的字形,将汉字放入n行*n列的正方形(即点阵)内,该正方形共有n^2个小方格,每个小方格用一位二进制数表示,凡是笔划经过的方格其值为1,未经过的方格其值为0。

2.

显示一个汉字一般采用16×16点阵或24×24点阵或48×48点阵。已知汉字点阵的大小,可以计算出存储一个汉字所需占用的字节空间。

比如,用16×16点阵表示一个汉字,就是将每个汉字用16行,每行16个点表示,一个点需要1位二进制数,16个点需用16位二进制数(即2个字节),所以需要16行×2字节/行=32字节,即以16×16点阵来表示一个汉字,字形码需要32字节。

因此,字节数=点阵行数×(点阵列数/8)。

3.

显然,字形码所表示的字符,相对于抽象字符表ACR里的“抽象”字符,可称之为“具体”字符,因为已经具有了“具体”的外形。

4.

为了将汉字的字形显示输出或打印输出,汉字信息处理系统还需要配有汉字字形库,也称字模库,简称字库,它集中存储了汉字的字形信息。

字库按输出方式可分为显示字库和打印字库。用于显示输出的字库叫显示字库,工作时需调入内存。用于打印输出的字库叫打印字库,工作时无需调入内存。

字库按存储方式也可分为软字库和硬字库。软字库以字体文件(即字形文件)的形式存放在硬盘上,现多用这种方式。硬字库则将字库固化在一个单独的存储芯片中,再和其它必要的器件组成接口卡,插接在计算机上,通常称为汉卡。这种方式现已淘汰。

七、总结

1.

可以这样理解,为在计算机内表示汉字而采取统一的编码方式所形成的汉字编码叫内码。为方便汉字输入而形成的汉字编码为外码,也叫输入码。为显示输出和打印输出汉字而形成的汉字编码为字形码,也称为字模码、输出码。

通过键盘输入汉字外码,然后输入法将汉字外码转换为当前操作系统所默认采用的字符编码方案的字符编号(即码点值),再根据字符编号通过代码页查表的方式转换为汉字内码(代码页详见前文的介绍),以实现输入汉字的目的;然后根据所选择的字体,通过汉字内码在字模库(即字库)中找出与字体相对应的字形码,从而将汉字内码转换为汉字字形码,以实现显示输出和打印输出汉字的目的。

事实上,英文字符的输入、处理和显示过程大致上也差不多,只不过英文字符不需要输入码(即外码),直接在键盘上输入对应的英文字母即可。

2.

注意,ASCII码,以及EASCII、ISO 8859系列、GB系列、Big5和Shift JIS等既兼容ASCII码又互相之间不兼容的ANSI编码(“ANSI编码”是对世界上各个国家和地区所制定的既兼容ASCII码又互相之间不兼容的各种字符编码的统称,下一篇文章将详细介绍这个统称的来龙去脉),都属于传统字符编码模型,而不属于现代字符编码模型,很难直接简单套用现代字符编码模型中的概念来表述。

如果一定要套用的话,就GB系列编码而言,勉强来说,区位码相当于现代字符编码模型中编号字符集CCS的字符编号,国标码相当于字符编码方式CEF的码元序列,而机内码则相当于字符编码模式CES的字节序列。

不过,由于GB系列编码虽然是多字节编码,但码元却是单字节码元(码元的概念后文有详细介绍),因此不存在字节序问题,也就不存在字符编码模式CES中的大端序、小端序的概念(字节序以及大端序、小端序的概念后文有详细介绍)。

(笨笨阿林原创文章,转载请注明出处)

【预告:下一篇将重点剖析非常容易令人困惑的所谓ANSI编码与代码页(Code Page),敬请关注!

0x80~0x9f 在ISO 8859中是C1控制字符,兼容原因

【转】刨根究底字符编码之六——简体汉字编码中区位码、国标码、机内码、外码、字形码的区别及关系相关推荐

  1. 刨根究底字符编码之六——简体汉字编码中区位码、国标码、内码、外码、字形码的区别及关系

    简体汉字编码中区位码.国标码.内码.外码.字形码的区别及关系 GB2312.GBK.GB18030等GB类汉字编码方案的具体实现方式是怎样的?区位码是什么?国标码是什么?内码.外码.字形码又是什么意思 ...

  2. mysql外码内码定义_刨根究底字符编码之六——简体汉字编码中区位码、国标码、内码、外码、字形码的区别及关系...

    简体汉字编码中区位码.国标码.内码.外码.字形码的区别及关系 GB2312.GBK.GB18030等GB类汉字编码方案的具体实现方式是怎样的?区位码是什么?国标码是什么?内码.外码.字形码又是什么意思 ...

  3. 【转】刨根究底字符编码之五——简体汉字编码方案(GB2312、GBK等)以及全角、半角、CJK

    一.概述 1. 英文字母再加一些其他标点字符之类的也不会超过256个,用一个字节来表示一个字符就足够了(2^8 = 256).但其他一些文字不止这么多字符,比如中文中的汉字就多达10多万个,一个字节只 ...

  4. 【转】刨根究底字符编码【2.0版】(1):开篇

    首先跟大家分享一个有趣的亲身经历.有一次,在网上我看到有程序员发了一个帖子,帖子题目乍一看让人感到惊愕,但细一想又让我会心一笑. 这个帖子的题目大致上是这样的:字符编码是不是让程序员最感到恶心的问题? ...

  5. 【转】刨根究底字符编码之零——前言

    前言 一. 字符编码是计算机世界里最基础.最重要的一个主题之一.不过,在计算机教材中却往往浮光掠影般地草草带过,甚至连一本专门进行深入介绍的著作都找不到(对这一点我一直很困惑,为什么就没有哪位大牛对这 ...

  6. 【转】刨根究底字符编码之十六——Windows记事本的诡异怪事:微软为什么跟联通有仇?

    1. 当用一个软件(比如Windows记事本或Notepad++)打开一个文本文件时,它要做的第一件事是确定这个文本文件究竟是使用哪种编码方式保存的,以便于该软件对其正确解码,否则将显示为乱码. 一般 ...

  7. 【转】刨根究底字符编码之十三——UTF-16编码方式

    1. UTF-16编码方式源于UCS-2(Universal Character Set coded in 2 octets.2-byte Universal Character Set).而UCS- ...

  8. 【转】刨根究底字符编码之十一——UTF-8编码方式与字节序标记BOM

    一.UTF-8编码方式 1. 接下来将分别介绍Unicode字符集的三种编码方式:UTF-8.UTF-16.UTF-32.这里先介绍应用最为广泛的UTF-8. 为满足基于ASCII.面向字节的字符处理 ...

  9. 计算机底层:ASCII码、区位码、国标码、汉字机内码,还有字形码和输入输出编码之间的关系以及介绍

    计算机底层:ASCII.区位码.国标码.汉字机内码之间的关系,还有字形码和输入输出编码之间的关系以及介绍 键盘上有:数字.字母.符合.这些都称作为字符,而它们的组合就叫做:字符串. ASCII 键盘上 ...

  10. 【转】刨根究底字符编码之七——ANSI编码与代码页

    一.ANSI编码 1. 如前所述,在全世界所有国家和地区的文字符号统一编码的UCS/Unicode编码方案问世之前(UCS.Unicode后文有详细介绍),各个国家.地区为了用计算机记录并显示自己的字 ...

最新文章

  1. websocket并发性测试
  2. 【Android 逆向】Android 进程注入工具开发 ( 总结 | 源码编译 | 逆向环境搭建使用 | 使用进程注入工具进行逆向操作 ) ★★★
  3. 【计算机网络】网络层 : 总结 ( 功能 | 数据交换 | IP 数据报 | IPv4 地址 | IPv6 地址 | 路由选择协议 | 路由算法 )★★★
  4. logback 的 filter
  5. 实现点击按钮后,倒计时60秒才能再次点击
  6. CSharp 如何OCR离线识别文本
  7. jzoj1405-电缆建设【贪心,最小生成树】
  8. C#的protected internal
  9. [转载] 消除vscode安装pylint后提示的unused variable
  10. HttpReponse
  11. 「12」你们啊,naive!——朴素贝叶斯谈笑录
  12. 【渝粤教育】国家开放大学2018年春季 8618-21T燃气行业规范 参考试题
  13. Cocos2dx源码记录(3) CCVertexIndexData
  14. Windows Server 2008 计划任务配置(任务计划程序)每分钟执行BAT
  15. 当想给下一个请求发送同享的数据时候 可以使用域对象设置属性
  16. iOS 取消多余tableView的横线的写法
  17. SLAM:一:产品经理眼中的SLAM技术学习路径
  18. STM32分别实现温湿度的采集和OLED显示屏显示数据
  19. BackTrack 4 R1 – Public Release
  20. element 时间选择器 限制时分秒_关于elementUI里日期选择器禁用时间的一些小技巧...

热门文章

  1. 德保罗大学计算机排名,德保罗大学费用
  2. python- 小猫钓鱼纸牌游戏
  3. 慢就是快的人生哲理_快和慢人生感悟
  4. 离散数学 —— 二元关系(恒等关系、关系图与关系矩阵、复合关系、自反与反自反、对称与反对称、传递性、闭包、等价类、商集、集合的划分、序关系、哈斯图、上下界函数)
  5. 计算机病毒进化趋势,人类进化趋势是什么?
  6. Tone mapping进化论
  7. SAP HANA语法中单引号、双引号用法
  8. python 顺序读取文件夹下面的文件(自定义排序方式)
  9. Invalid bound statement (not found): org.seckill.dao.Suc
  10. SBC音频编解码算法浅析