Debian中文环境配置及几种中文编码的探究
国际化(Internationalization,简写为I18N)是指软件能用于多国语言环境的能力,它在系统的低层函数库中提供一组标准的函数接口,能根据本地化(locale)设置显示该地区语言环境的信息。本地化(Localization
简写为L10N)是指将本地区的语言环境数据安装在系统底层的数据库中,以便让系统函数存取来显示正确的文字信息。多语言化(Multilingualization
简写为M17N)是指程序可以处理多种语言的过程。本地化和多语言化都是国际化框架中的组成部份。
本地化在Linux中通过locale来设置程序运行的不同语言环境,locale是(Local
Environment)的缩写,它是一个语言环境数据库。locale的命名规则为语言>_地区>.字符集编码>,如zh_CN.UTF-8,zh代表中文,CN代表大陆地区,UTF-8表示字符集编码方式。在locale环境中,有一组变量,代表国际化环境中的不同设置:
1.
LC_COLLATE
定义该环境的排序和比较规则
2.
LC_CTYPE
用于字符分类和字符串处理,控制所有字符的处理方式,包括字符编码,字符是单字节还是多字节,如何打印等。是最重要的一个环境变量。
3.
LC_MONETARY
货币格式
4.
LC_NUMERIC
非货币的数字显示格式
5.
LC_TIME
时间和日期格式
6.
LC_MESSAGES
应用程序显示信息的语言。另外还有一个LANGUAGE参数,它与LC_MESSAGES相似,但如果该参数一旦设置,则LC_MESSAGES参数就会失效。LANGUAGE参数可同时设置多种语言信息,如LANGUANE="zh_CN.GB18030:zh_CN.GB2312:zh_CN"。
7.
LANG
LC_*的默认值,是最低级别的设置,如果LC_*没有设置,则使用该值。类似于 LC_ALL。
8.
LC_ALL
它是一个宏,如果该值设置了,则该值会覆盖所有LC_*的设置值。注意,LANG的值不受该宏影响。
一个例子:
设置前,使用默认locale:
debian:~# locale
LANG="POSIX"
LC_CTYPE="POSIX"
LC_NUMERIC="POSIX"
LC_TIME="POSIX"
LC_COLLATE="POSIX"
LC_MONETARY="POSIX"
LC_MESSAGES="POSIX"
LC_PAPER="POSIX"
LC_NAME="POSIX"
LC_ADDRESS="POSIX"
LC_TELEPHONE="POSIX"
LC_MEASUREMENT="POSIX"
LC_IDENTIFICATION="POSIX"
LC_ALL=
设置后,使用zh_CN.GBK中文locale:
debian:~# export LC_ALL=zh_CN.GBK
debian:~# locale
LANG=zh_CN.UTF-8
LC_CTYPE="zh_CN.GBK"
LC_NUMERIC="zh_CN.GBK"
LC_TIME="zh_CN.GBK"
LC_COLLATE="zh_CN.GBK"
LC_MONETARY="zh_CN.GBK"
LC_MESSAGES="zh_CN.GBK"
LC_PAPER="zh_CN.GBK"
LC_NAME="zh_CN.GBK"
LC_ADDRESS="zh_CN.GBK"
LC_TELEPHONE="zh_CN.GBK"
LC_MEASUREMENT="zh_CN.GBK"
LC_IDENTIFICATION="zh_CN.GBK"
LC_ALL=zh_CN.GBK
"C"是系统默认的locale,"POSIX"是"C"的别名。所以当我们新安装完一个系统时,默认的locale就是C或POSIX。
在Debian中安装locales的方法如下:
·
通过apt-get
install locales命令安装locales包
·
安装完成locales包后,系统会自动进行locale配置,你只要选择所需的locale,可以多选。最后指定一个系统默认的locale。这样系统就会帮你自动生成相应的locale和配置好系统的locale。
·
增加新的locale也很简单,用dpkp-reconfigure
locales重新配置locale即可。
·
我们也可手动增加locale,只要把新的locale增加到/etc/locale.gen文件中,再运行locale-gen命令即可生成新的locale。再通过设置上面介绍的LC_*变量就可设置系统的locale了。下是一个locale.gen文件的样例。
· # This file lists locales that you wish to have built. You can find a list
· # of valid supported locales at /usr/share/i18n/SUPPORTED. Other
· # combinations are possible, but may not be well tested. If you change
· # this file, you need to rerun locale-gen.
· #
· zh_CN.GBK GBK
· zh_CN.GB18030 GB18030
· zh_CN.UTF-8 UTF-8
在安装了locale支持的系统中,在/usr/share/locale目录下保存locale的信息,在/usr/share/consolefonts目录下保存字体信息,在/usr/lib/gconv目录下保存字符转换模块的信息。总结:如果要在Linux下正确显示中文信息,需要做以下工作。
·
系统本身要有国际化支持,Linux的国际化支持是很完善的。
·
安装本地locale,如:zh_CN.GB2312、zh_CN.GBK、zh_CN.GB18030、zh_CN.UTF-8等。
·
安装中文字体,如:文泉驿和文鼎的中文字体等。
·
设置中文的环境变量,如:LANG=zh_CN.GB2312、LANG=zh_CN.UTF-8等。有几个地方都可以设置locale环境变量。
o
一个是在X
Window的登录管理器中可以设置,如GDM、KDM。
o
一个是在X Window
Session初始化时设置,在/etc/X11/Xsession.d目录下的所有脚本在X Window
Session初始化时都会自动运行,所以我们可把export
LANG="zh_CN.GB18030"这条设置命令放到任意的脚本中。建议放到中文输入法的启动脚本中。示例:(这是我手工创建的启动fcitx中文输入法的脚本91fcitx)
o debian:/etc/X11/Xsession.d# cat 91fcitx
o export LANG="zh_CN.UTF-8"
o export XMODIFIERS="@im=fcitx"
o export XIM_PROGRAM=fcitx
o export XIM=fcitx
o fcitx&
o
在shell的启动脚本中设置,如在.bashrc、.bash_profile等文件中直接加入export
LANG="zh_CN.UTF-8"命令。
o
还可以在shell中直接用export
LANG="zh_CN.UTF-8"命令设置。但如果使用该命令设置的环境变量只在当前shell中有效。
·
在应用程序中配置使用中文显示。
要在Shell中正常显示系统的中文提示信息和支持中文输入。LANG和shell的编码配置需一致,并安装有中文locale。如:LANG和shell的编码都配置成zh_CN.utf8,并安装有zh_CN.utf8这个locale。如果shell和LANG配置不同,则中文显示乱码;如果LANG里设置的locale没有安装,则不能显示系统的中文提示信息,只会显示英文提示信息。
在不同的locale环境下会生成具有不同编码的文件,如在gb2312环境下创建的文件就具有gb2312编码,在utf-8环境下创建的文件就具有utf-8编码。如果我们在gb2312环境下打开utf-8编码的文件中文部份就会显示乱码。在Linux中有一个叫iconv的程序可以帮助我们进行文件编码的转换工作。下面的示例是把一个使用gb2312编码的文件转换成utf-8编码的文件:
debian:~/Desktop# iconv -f gb2312 -t utf-8 7月.txt -o 77.txt
-f选项指定源文件的编码,-t选项指定转换后文件的编码,7月.txt是要转换的文件,-o选项指定转换后输出的文件名。
另注:
内码是指操作系统内部的字符编码。早期操作系统的内码是与语言相关的.现在的Windows
在内部统一使用Unicode,然后用代码页适应各种语言,“内码”的概念就比较模糊了。微
软一般将缺省代码页指定的编码说成是内码,在特殊的场合也会说自己的内码是Unicode,
例如在GB18030问题的处理上。
所谓代码页(code page)就是针对一种语言文字的字符编码。例如GBK的code page是CP936,BIG5的code page是CP950,GB2312的code page是CP20936。微软也为GB18030定义了code page:CP54936。但是由于GB18030有一部分4字节编码,而Windows的代码页只支持单字节和双字节编码,所以这个code page是无法真正使用的。
Windows中有缺省代码页的概念,即缺省用什么编码来解释字符。例如Windows的记事本打
开了一个文本文件,里面的内容是字节流:BA、BA、D7、D6。Windows是按照Unicode编码解释、还是按照GBK、或者按照BIG5,又或者按照ISO8859-1去解释?如果按GBK去解释,就会得到“汉字”两个字。按照其它编码解释,可能找不到对应的字符,也可能找到错误的字符。所谓“错误”是指与文本作者的本意不符,这时就产生了乱码。
答案是Windows按照当前的缺省代码页去解释文本文件里的字节流。缺省代码页可以通过控
制面板的区域选项设置。记事本的“另存为”功能中有一项ANSI,其实就是按照缺省代码页的编码方法保存。
Windows的内码是Unicode,它在技术上可以同时支持多个代码页。只要文件能说明自己使
用什么编码,用户又安装了对应的代码页,Windows就能正确显示,例如在HTML文件中就可
以指定charset。有的HTML文件作者,特别是英文作者,认为世界上所有人都使用英文,在文件中不指定charset。如果他使用了0x80-0xff之间的字符,中文Windows又按照缺省的GBK去解释,就会出现乱码。这时需要在这个html文件中加上指定charset的语句,例如:如果原作者使用的代码页和ISO8859-1兼容,就不会出现乱码了。
GB18030编码研究以及GBK、GB18030与Unicode的映射
GB18030有两个版本:GB18030-2000和GB18030-2005。在本文中,没有指明版本的GB18030是指GB18030-2005。本文讨论了以下问题:
GB2312有682个图形符号,都放在1区。GBK的1区有717个图形符号,5区有
166个图形符号,一共有883个图形符号。GB18030的1区有728个图形符号,5区还是166个符号。那么,GBK的1区在GB2312基础上增
加了哪35个符号?GB18030又增加了哪些符号?
GBK支持21003个汉字与883个图形符号,一共21886个字符。这21886个字符究竟是哪些字符?这21886个字符的编码在GB18030中有什么变化?
GB18030是怎样映射Unicode的全部0x110000个码位的?
GB18030-2000和GB18030-2005在字汇上有什么区别,在编码上有什么区别?
GB18030-2005的双字节区中有2067个码位被映射到Unicode BMP的PUA。这些码位有什么规律?这些码位中定义了多少字符?其实这2067个码位中只定义了24个字符。
GBK的21886个字符中有95个字符被映射到Unicode BMP的PUA。在GB18030中这95个字符的编码有哪些变化?哪些字符保持了原来的编码?
GBK的23940个码位中有多少码位被映射到Unicode BMP的PUA?在GB18030中这些码位的编码有什么变化?
在讨论这些问题前,我们先约定一下码位空间的表示方法。
0 码位空间
0.1 约定
GBK是双字节编码,每个字符用两个字节表示。GB18030是多字节字符集,它的字符可以用一个、两个或四个字节表示。码位空间由各字节的范围确定。例如:GB18030的四字节字符码位空间是:
第一字节在0x81~0xFE之间
第二字节在0x30~0x39之间
第三字节在0x81~0xFE之间
第四字节在0x30~0x39之间
为了表述方便,我们用0x81308130~0xFE39FE39表示这个码位空间。也就是说:在本文中0x81308130~0xFE39FE39所指的并不是从0x81308130到0xFE39FE39的连续2097773834(0xFE39FE39-0x81308130+1)个字节。在本文中,0x81308130~0xFE39FE39所指的是编码的各字节在对应范围内的码位空间,这个码位空间的码位数目是:
(0xFE-0x81+1)*(0x39-0x30+1)*(0xFE-0x81+1)*(0x39-0x30+1)=126*10*126*10=1587600
同理,0xB0A1~0xF7FE代表的码位空间是第一字节在0xB0~0xF7之间,第二字节在0xA1~0xFE之间的所有码位。这个码位空间的码位数目是:
(0xF7-0xB0+1)*(0xFE-0xA1+1)=72*94=6768
这个码位空间就是GBK和GB18030的2区,在这6768个码位中定义了6763个字符。
本文用~表示上述码位空间,用-表示一般的范围,即:
0xA1A1~0xA9FE 表示第一字节在0xA1到0xA9之间,第二字节在0xA1~0xFE之间的846((0xA9-0xA1+1)*(0xFE-0xA1+1)=9*94)个码位。
0xE000-0xF8FF 表示从0xE000-0xF8FF的连续6400(0xF8FF-0xE000+1)个码位。
0.2 习题
读者如果已经理解了上面的约定,请完成下面两个习题:
习题一:求码位空间0x8140~0xFE7E的码位数目。
习题二:求码位空间0x8180~0xFEFE的码位数目。
0.3 答案
以下是习题0.2的答案:
习题一:(0xFE-0x81+1)*(0x7E-0x40+1)=126*63=7938
习题二:(0xFE-0x81+1)*(0xFE-0x80+1)=126*127=16002
GB18030双字节字符的码位空间就是0x8140~0xFE7E和0x8180~0xFEFE,双字节字符的码
位数目是7938+16002=23940。0x8140~0xFE7E和0x8180~0xFEFE也是GBK的全部码位空间。GBK在这23940个
码位中定义了21886个字符。
1 GBK回顾
1.1 简介
GBK是双字节编码方案。它的码位空间就是前面所说的0x8140~0xFE7E和0x8180~0xFEFE,一共23940个码位。在这23940个码位上定义了21886个字符,包括21003个汉字和883个图形符号。
《Unicode、GB2312、GBK和GB18030中的汉字》
详细讨论了这21003个汉字。本文的第3节会讨论GB2312、GBK和GB18030的图形符号。
GBK的码位空间可以划分为以下区域:
类别
区名
码位范围
码位数
字符数
符号区
1区
0xA1A1~0xA9FE
846
717
5区
0xA840~0xA97E和0xA880~0xA9A0
192
166
汉字区
2区
0xB0A1~0xF7FE
6768
6763
3区
0x8140~0xA07E和0x8180~0xA0FE
6080
6080
4区
0xAA40~0xFE7E和0xAA80~0xFEA0
8160
8160
用户自定义区
用户区1
0xAAA1~0xAFFE
564
用户区2
0xF8A1~0xFEFE
658
用户区3
0xA140~0xA77E和0xA180~0xA7A0
672
1.2 GBK字符与Unicode的映射
我制作了一个Excel文件:
附件1
。这个文件包含3张表格:
按照GBK编码排序的GBK全部21886字符码表。这个表格有3列:字符、GBK编码、Unicode编码。
按照Unicode编码排序的GBK全部21886字符码表。这个表格有3列:字符、Unicode编码、GBK编码。
从
按Unicode编码排序的表格中,很容易找到被映射到PUA(0xE000-0xF8FF)的字符。GBK的21886个字符中有95个字符属于
PUA。第三张表格列出了这95个字符(A列)的GBK编码(B列)、Unicode编码(C列)以及这些字符在GB18030中对应的Unicode编
码(D列)。
其中D列可能不太容易理解,我再解释一下。GB18030是兼容GBK的,所以这些字符的GBK编码和GB18030编码是相同的。
例如的GBK编码和GB18030编码都是0xA8BF。但是在GBK和GB18030中,被映射到不同的Unicode码位。在GBK
中,0xA8BF被映射到Unicode的0xE7C8。在Unicode中,码位0xE7C8是一个PUA码位,保留给用户使用。在GB18030
中,0xA8BF被映射到Unicode的0x01F9。在Unicode中,码位0x01F9属于“拉丁字母扩充-B”这个Block,这个码位定义的
字符是“带抑音符的拉丁文小写字母 N”,字形就是。
1.3 GBK码位与Unicode的映射
GBK的23940个码位定义了21886个字符,还有23940-21886=2054个空闲码位,这2054个
码位都被映射到Unicode的PUA。在设计GBK时,GBK的21886个字符中有95个在Unicode中没有对应字符,所以这95个字符也被映射
到Unicode的PUA。在GBK的23940个码位中,一共有2054+95=2149个码位被映射到PUA,对应的PUA编码是
0xE000-0xE864。0xE000-0xE864就是2149个码位。这2149个码位的分配有以下规律:
码位所在区域
码位数量
映射到的PUA范围
用户区1:0xAAA1~0xAFFE
564
0xE000-0xE233
用户区2:0xF8A1~0xFEFE
658
0xE234-0xE4C5
用户区3:0xA140~0xA77E和A180-A7A0
672
0xE4C6-0xE765
符号区(1区和5区)的170个空闲码位
170
0xE766-0xE80F
2区的5个空闲码位:0xD7FA-0xD7FE
5
0xE810-0xE814
4区的80个Unicode当时没有定义的字符:FE50-FE7E和FE80-FEA0
80
0xE815-0xE864
附件2
包含两张表格:
23940个GBK码位与Unicode的映射。两组数据分别按GBK和Unicode排序。
2149个映射到PUA的码位,按Unicode顺序排列。
2 GB18030编码
2.1 概述
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个字符。
2.2 设计思路
GB18030编码可以分为:单字节部分、双字节部分和四字节部分。单字节部分与Unicode的0x00-0x7f完全相同。双字节部分与GBK有两点差异:
在1区增加了11个字符。这样1区就有717+11=728个字符。增加的11个字符是:一个欧元符号(0xA2E3)和10个竖排标点符号(0xA6D9-0xA6DF、0xA6EC-0xA6ED和0xA6F3)。
原来因为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的设计思路可以概括到以下几点:
单字节部分与Unicode一致。
双字节部分与GBK兼容。适当调整一些字符与Unicode的映射。这些字符原来因为Unicode没有收录而被映射到PUA,现在因为Unicode已经收录而调整到非PUA的Unicode码位。
将Unicode BMP部分还没有映射的39420个码位顺序映射到从0x81308130开始的四字节部分。
将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码位。
2.3 GB18030-2000和GB18030-2005的区别及以后版本
GB18030-2005与GB18030-2000的编码体系结构是完全相同的。GB18030-2005相对于GB18030-2000主要有以下变化:
在四字节字符表中增加CJK统一汉字扩充B和已经在GB13000中编码的我国少数民族文字字符的字形。其实GB18030-2000已经映射了这些码位,但GB18030-2000没有给出这些字符的字形。
调整字符的编码。
其中的编码调整比较有意思。的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码位。调整方法应该与的调整方法相同。
2.4 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的映射没有规律,只能通过查表方法映射。
2.5 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个一级区是保留区或自定义区。
2.5.1 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)
2.6 GB18030和Unicode的映射表
附件3
给出了GB18030和Unicode的映射表。这个Excel文件是在网友谢振斌先生的
映射表
基础上制作的,包含3张表格:
双字节部分23940个码位与Unicode的映射。两组数据分别按GB18030和Unicode排序。
BMP扩展部分39420个码位与Unicode的映射。两组数据分别按GB18030和Unicode排序。
辅助平面部分,GB18030编码和Unicode编码的映射公式。
3 GB2312、GBK和GB18030中的图形符号
在研究GB18030编码的过程中,我整理了GB2312、GBK和GB18030在1区和5区的图形符号,制作了
附件4
。这个Excel文件包含3张表格:
GB2312的1区字符表。GBK和GB18030的1区、5区字符表。用不同颜色标注了GBK增加的35个字符和GB18030增加的11个字符。
GB2312 1区682个符号的编码。
GBK 1区717个符号的编码。
结束语
通过本文的介绍,读者可以回答开头的问题了吗?
无论是Windows
XP还是Vista,中文(中国)区域对应的默认代码页还是GBK。我们只能设置区域,并不能设置区域对应的默认代码页。所以在Windows世界,只要微软不愿意,GB18030就只是一张普通的代码页。目前的简体中文文档使用的编码主要是Unicode和GBK,本文对GB18030编码所作的一些研究,希望能对对GB18030感兴趣的读者有所助益。