欢迎各位兄弟 发布技术文章

这里的技术是共享的

You are here

GB18030码位、设计思路、2000和2005的差别、双字节和四字节的个性及与Unicode的映射

shiping1 的头像

码位:

GB18030是多字节字符集,它的字符可以用一个、两个或四个字节表示。GB18030的码位定义如下:

字节数 码位空间 码位数 字符数 单字节 0x00~0x7F 128 128 双字节 0x8140~0xFE7E和0x8180~0xFEFE 23940 21897 四字节 0x81308130~0xFE39FE39 1587600 54531

GB18030有128+23940+1587600=1611668个码位。Unicode的码位数目是0x110000(1114112),少于GB18030。所以,GB18030有足够的空间映射Unicode的所有码位。

GB18030的1611668个码位目前定义了128+21897+54531=76556个字符。Unicode 5.0定义了99089个字符。

GB18030编码可以分为:单字节部分、双字节部分和四字节部分。单字节部分与Unicode的0x00-0x7f完全相同。双字节部分与GBK有两点差异:

  1. 在1区增加了11个字符。这样1区就有717+11=728个字符。增加的11个字符是:一个欧元符号(0xA2E3)和10个竖排标点符号(0xA6D9-0xA6DF、0xA6EC-0xA6ED和0xA6F3)。
  2. 原来因为Unicode没有收录而映射到PUA的字符中的部分字符被新版本的Unicode收录,所以将这些字符映射到非PUA的码位。

Unicode的BMP一共有65536个码位。其中代理区(0xD800-0xDFFF)有2048个码位,这2048个码位是不能定义字符的。GB18030的单字节部分映射了128个码位,GB18030的双字节部分映射了23940个码位。还剩下65536-2048-128-23940=39420个码位。

GB18030将这39420个码位顺序映射到从0x81308130开始的码位空间。GB18030将Unicode的16个辅助平面(0x10000-0x10FFFF,一共1048576个码位)顺序映射到从0x90308130开始的码位空间。GB18030四字节部分中只有这两个区域定义了字符,其它空间都是保留区和自定义区。本文的第3节和第4节还会详细讨论GB18030的双字节和四字节部分。

GB18030的设计思路可以概括到以下几点:

  1. 单字节部分与Unicode一致。
  2. 双字节部分与GBK兼容。适当调整一些字符与Unicode的映射。这些字符原来因为Unicode没有收录而被映射到PUA,现在因为Unicode已经收录而调整到非PUA的Unicode码位。
  3. 将Unicode BMP部分还没有映射的39420个码位顺序映射到从0x81308130开始的四字节部分。
  4. 将Unicode BMP以外的16个辅助平面映射到39420个码位顺序映射到从0x90308130开始的四字节部分。

在GB18030目前定义的76556个字符中,只有24个字符被定义到Unicode的PUA区。这24个字符包括1区的10个竖排标点符号(0xA6D9-0xA6DF、0xA6EC-0xA6ED和0xA6F3)和4区的14个汉字(0xFE51、0xFE52、0xFE53、0xFE59、0xFE61、0xFE66、0xFE67、0xFE6C、0xFE6D、0xFE76、0xFE7E、0xFE90、0xFE91、0xFEA0)。4区的14个汉字在Unicode 5.0中其实也可以找到非PUA的编码,详见《Unicode、GB2312、GBK和GB18030中的汉字》。但按照GB18030,它们还是应该映射到PUA码位。

GB18030-2000和GB18030-2005的区别及以后版本

GB18030-2005与GB18030-2000的编码体系结构是完全相同的。GB18030-2005相对于GB18030-2000主要有以下变化:

  1. 在四字节字符表中增加CJK统一汉字扩充B和已经在GB13000中编码的我国少数民族文字字符的字形。其实GB18030-2000已经映射了这些码位,但GB18030-2000没有给出这些字符的字形。
  2. 调整字符 的编码。

其中 的编码调整比较有意思。 的GB18030编码是0xA8BC, 在Unicode 5.0的编码是0x1E3F。在GB18030-2000中0xA8BC被映射到Unicode的0xE7C7,因为双字节部分没有映射0x1E3F,所以它作为BMP的未映射字符被放到四字节部分的0x8135F437。GB18030-2005将0xA8BC映射到0x1E3F,那么Unicode码位0xE7C7怎么办呢?为了最小化对原来编码的影响,设计者将Unicode码位0xE7C7映射到本来映射0x1E3F的0x8135F437。

GB18030已经映射了Unicode的所有码位,所以不管Unicode怎么变化,GB18030不过就是在现在的码位上增加一些字形而已,编码不会变化。只有现在还映射到PUA的24个字符以后可能会调整到非PUA码位。调整方法应该与 的调整方法相同。

GB18030双字节部分

前面已经介绍过GB18030双字节部分与GBK的区别,本小节再提一些细节。前面也说过,GB18030映射了Unicode除代理区外的所有码位。所以,Unicode BMP的6400个PUA码位在GB18030中都有对应的码位。GB18030双字节部分映射了2067个PUA码位。

前面说过,GBK映射了2149个PUA码位。现在GB18030双字节部分映射了2067个PUA码位。所以有2149-2067=82个字符的映射发生了变化。GBK原来有95个字符映射到PUA,其中81个字符在GB18030中被映射到非PUA码位。余下的14个汉字就是《Unicode、GB2312、GBK和GB18030中的汉字》提到的那14个汉字(0xFE51、0xFE52、0xFE53、0xFE59、0xFE61、0xFE66、0xFE67、0xFE6C、0xFE6D、0xFE76、0xFE7E、0xFE90、0xFE91、0xFEA0)。附件1列出了这些字符的编码变化。82个映射变化的码位,除了这81个外,还有一个就是欧元符号:GB18030编码是0xA2E3,Unicode编码是0x20AC。码位0xA2E3在GBK中被映射到0xE76C,GBK的码位0xA2E3没有定义字符。

GB18030双字节部分与Unicode的映射没有规律,只能通过查表方法映射。

GB18030四字节部分

GB18030四字节部分的字符可以见GB18030-2005的“表3 四字节部分的码位安排”,一共54531个字符。GB18030四字节部分的码位可以见GB18030-2005的“7.3 四字节部分字符的排列顺序”。其中定义字符的只有两个区域:

  • GB18030用码位0x81308130~0x8439FE39共50400个码位映射该标准单字节和双字节部分没有映射过的39420个Unicode BMP码位。
  • GB18030用码位0x90308130~0xE339FE39共1058400个码位映射Unicode 16个辅助平面(平面1到平面16)的65536*16=1048576个码位。

为了叙述方便,本文将0x81308130~0x8439FE39称作“BMP扩展部分”,将0x90308130~0xE339FE39称作“辅助平面部分”。GB18030四字节部分的码位空间是0x81308130~0xFE39FE39。第二字节有(0x39-0x30+1)=10个可能值。第三字节有(0xFE-0x81+1)=126个可能值。第四字节也是(0x39-0x30+1)=10个可能值。为了方便下面的演算,本文为这个码位空间定义几个名词:

  • 我们将四字节码位空间中第一字节相同的区域称作一级区。每个一级区有12600个码位,即:10*126*10。
  • 我们将四字节码位空间中第一字节和第二字节相同的区域称作二级区。每个二级区有1260个码位,即:126*10。
  • 我们将四字节码位空间中前三个字节相同的区域称作三级区,每个三级区有10个码位。

四字节部分一共有(0xFE-0x81+1)=126个一级区。BMP扩展部分有4个一级区。辅助平面部分有84个一级区。还有38个一级区是保留区或自定义区。

BMP扩展部分

BMP扩展部分占据四字节部分开头的4个一级区,一共有4*12600=50400个码位。这段空间的Unicode映射说起来还是很简单的,就是顺序映射单字节、双字节没有映射过的BMP码位。这些映射关系在GB18030-2000中确定下来。以后的调整(例如 )只是个别字符,不会影响其它字符的位置。但是因为双字节字符已经映射过的BMP码位没有什么规律,所以造成BMP扩展部分的Unicode映射也不能用公式换算,还是要查表解决。

显然这50400个码位中只用到了39420个码位,其余码位都是保留的。出于好玩,我们来计算一下最后一个非保留码位(0xFFFF)的位置,计算过程如下:

  • m1=(39420-1)/12600=3
  • n1=(39420-1)%12600=1619
  • m2=n1/1260=1619/1260=1
  • n2=n1%1260=1619%1260=359
  • m3=n2/10=359/10=35
  • n3=n2%10=359%10=9
  • 第一字节的位置是:0x81+m1=0x81+3=0x84
  • 第二字节的位置是:0x30+m2=0x30+1=0x31
  • 第三字节的位置是:0x81+m3=0x81+35=0xA4
  • 第四字节的位置是:0x30+n3=0x30+9=0x39

所以Unicode编码0xFFFF映射的GB18030码位是0x8431A439。在BMP扩展部分中,0x8431A439以后的码位都是保留码位。上述计算中,/表示整除(例如5/3=1),%表示取余(例如5%3=2)。

2.5.2 辅助平面部分

辅助平面部分用84个一级区(0x90308130~0xE339FE39)直接映射Unicode的16个辅助平面。这部分映射是可以直接用公式计算的。让我们看看怎么计算。

  • 从Unicode编码到GB18030编码的映射方法如下:
    • U=Unicode编码-0x10000
    • m1=U/12600
    • n1=U%12600
    • m2=n1/1260
    • n2=n1%1260
    • m3=n2/10
    • n3=n2%10
    • 第一字节b1=m1+0x90
    • 第二字节b2=m2+0x30
    • 第三字节b3=m3+0x81
    • 第四字节b4=n3+0x30
    按照上述方法可以计算出0x10FFFF被映射到0xE3329A35。在辅助平面部分,0xE3329A35以后的码位都是保留码位。以上所写的算法可以很容易写成C/C++代码。对于不会编程的读者,也可以用Excel公式计算。假设Unicode编码放在单元格A12,计算方法如下:
    • 将m1放在B12,B12=INT((HEX2DEC(A12)-65536)/12600)
    • 将n1放在C12,C12=MOD((HEX2DEC(A12)-65536),12600)
    • 将m2放在D12,D12=INT(C12/1260)
    • 将n2放在E12,E12=MOD(C12,1260)
    • 将m3放在F12,F12=INT(E12/10)
    • 将n3放在G12,G12=MOD(E12,10)
    • 将第一字节放在H12,H12=DEC2HEX(B12+144)
    • 将第二字节放在I12,I12=DEC2HEX(D12+48)
    • 将第三字节放在J12,J12=DEC2HEX(F12+129)
    • 将第四字节放在K12,K12=DEC2HEX(G12+48)
    附件3中有写好上述公式的Excel表格。使用函数HEX2DEC/DEC2HEX需要通过“工具->加载宏”钩上“分析工具库”。
  • 从GB18030编码到Unicode编码的映射方法如下:
    • 设GB18030编码的四个字节依次为:b1、b2、b3、b4,则
      Unicode编码=0x10000+(b1-0x90)*12600+(b2-0x30)*1260+(b3-0x81)*10+b4-0x30
    假设b1、b2、b3、b4分别放在A4、B4、C4、D4,Unicode编码放在E4,则Excel计算公式为:
    • E4 = =DEC2HEX((HEX2DEC(A4)-144)*12600+(HEX2DEC(B4)-48)*1260+(HEX2DEC(C4)-129)*10+(HEX2DEC(D4)-48)+65536)

与Unicode的映射

附件3给出了GB18030和Unicode的映射表。这个Excel文件是在网友谢振斌先生的映射表基础上制作的,包含3张表格:

  1. 双字节部分23940个码位与Unicode的映射。两组数据分别按GB18030和Unicode排序。
  2. BMP扩展部分39420个码位与Unicode的映射。两组数据分别按GB18030和Unicode排序。
  3. 辅助平面部分,GB18030编码和Unicode编码的映射公式。

也可以从下面附表中的部分内容看出一些端倪

双字节部分

GB18030 Unicode Unicode GB18030 8140 4E02 00A4 A1E8 8141 4E04 00A7 A1EC 8142 4E05 00A8 A1A7 8143 4E06 00B0 A1E3 8144 4E0F 00B1 A1C0 8145 4E12 00B7 A1A4 8146 4E17 00D7 A1C1 8147 4E1F 00E0 A8A4

BMP扩展部分

GB18030 Unicode 81308130 0080 81308131 0081 81308132 0082 81308133 0083 81308134 0084 81308135 0085 81308136 0086 81308137 0087 81308138 0088 81308139 0089

辅助平面部分

第一字节 第二字节 第三字节 第四字节 Unicode编码 95 32 82 36 20000 9A 34 84 31 2FFFF

Unicode m1 n1 m2 n2 m3 n3 第一字节 第二字节 第三字节 第四字节 20000 5 2536 2 16 1 6 95 32 82 36 2FFFF 10 5071 31 3 1 9A 34 84 31

普通分类: