Chinaunix首页 | 论坛 | 博客
  • 博客访问: 373965
  • 博文数量: 53
  • 博客积分: 1411
  • 博客等级: 上尉
  • 技术积分: 701
  • 用 户 组: 普通用户
  • 注册时间: 2008-11-04 14:40
文章分类

全部博文(53)

文章存档

2011年(6)

2010年(20)

2009年(18)

2008年(9)

我的朋友

分类: C/C++

2009-02-23 11:23:55

关于GB2312和Utf-8编码的转换,网上相关的文章似乎很多,不过真正可以拿过来就能用的,并不太多。在Windows和Linux系统中,都有编码直接转换的函数可以调用,不过在嵌入式系统中,就必须自己加载编码的转换表,来进行编码之间的相互转换了。本文给出相关的转换码表和转换函数,供需要者参考。


一 基础知识速览

GB2312简介

GB2312或GB2312-80是一个简体中文字符集的中国国家标准,全称为《信息交换用汉字编码字符集·基本集》,又称为GB0,由中国国家标准总局发布,1981年5月1日实施。GB2312编码通行于中国大陆;新加坡等地也采用此编码。中国大陆几乎所有的中文系统和国际化的软件都支持GB2312。

GB2312标准共收录6763个汉字,其中一级汉字3755个,二级汉字3008个;同时,GB 2312收录了包括拉丁字母、希腊字母、日文平假名及片假名字母、俄语西里尔字母在内的682个全角字符。

GB2312的出现,基本满足了汉字的计算机处理需要,它所收录的汉字已经覆盖中国大陆99.75%的使用频率。
对于人名、古汉语等方面出现的罕用字,GB 2312不能处理,这导致了后来GBK及GB 18030汉字字符集的出现。

GB2312分区存储

B 2312中对所收汉字进行了“分区”处理,每区含有94个汉字/符号。这种表示方式也称为区位码。
    * 01-09区为特殊符号。
    * 16-55区为一级汉字,按拼音排序。
    * 56-87区为二级汉字,按部首/笔画排序。
10-15区及88-94区则未有编码。
举例来说,“啊”字是GB2312之中的第一个汉字,它的区位码就是1601

GB2312字节结构

在使用GB2312的程序中,通常采用EUC储存方法,以便兼容于ASCII。浏览器编码表上的“GB2312”,通常都是指“EUC-CN”表示法。

每个汉字及符号以两个字节来表示。第一个字节称为“高位字节”,第二个字节称为“低位字节”。

“高位字节”使用了0xA1-0xF7(把01-87区的区号加上0xA0),“低位字节”使用了0xA1-0xFE(把01-94加上 0xA0)。由于一级汉字从16区起始,汉字区的“高位字节”的范围是0xB0-0xF7,“低位字节”的范围是0xA1-0xFE,占用的码位是 72*94=6768。其中有5个空位是D7FA-D7FE。

例如“啊”字在大多数程序中,会以两个字节,0xB0(第一个字节)0xA1(第二个字节)储存。(与区位码对比:0xB0=0xA0+16,0xA1=0xA0+1)。

UNICODE简介

Unicode(统一码、万国码、单一码、标准万国码)在计算机科学领域,是业界的一种标准,它可以使电脑得以呈现世界上数十种文字的系统。Unicode 是基于通用字符集(Universal Character Set)的标准来发展,并且同时也以书本的形式(The Unicode Standard,目前第五版由Addison-Wesley Professional出版,ISBN-10: 0321480910)对外发表。Unicode包含了超过十万个字符(在2005年,Unicode的第十万个字符被采纳且认可成为标准之一)、一组可用以作为视觉参考的代码图表、一套编码方法与一组标准字符编码、一套包含了上标字、下标字等字符特性的列举等。

UNICODE编码方式

Unicode 的编码方式与 ISO 10646 的通用字符集(Universal Character Set,UCS)概念相对应,目前实际应用的 Unicode 版本对应于 UCS-2,使用16位的编码空间。也就是每个字符占用2个字节。这样理论上一共最多可以表示 216 即 65536 个字符。基本满足各种语言的使用。实际上目前版本的 Unicode 尚未填充满这16位编码,保留了大量空间作为特殊使用或将来扩展。

上述16位 Unicode 字符构成基本多文种平面(Basic Multilingual Plane,简称 BMP)。最新(但未实际广泛使用)的 Unicode 版本定义了16个辅助平面,两者合起来至少需要占据21位的编码空间,比3字节略少。但事实上辅助平面字符仍然占用4字节编码空间,与 UCS-4 保持一致。未来版本会扩充到 ISO 10646-1 实现级别3,即涵盖 UCS-4 的所有字符。UCS-4 是一个更大的尚未填充完全的31位字符集,加上恒为0的首位,共需占据32位,即4字节。理论上最多能表示 231 个字符,完全可以涵盖一切语言所用的符号。

BMP 字符的 Unicode 编码表示为 U+hhhh,其中每个 h 代表一个十六进制数位。与 UCS-2 编码完全相同。对应的4字节 UCS-4 编码后两个字节一致,前两个字节的所有位均为0。

UTF-8简介

UTF-8是UNICODE编码的一种实现方式,它有以下特性:

    * UCS 字符 U+0000 到 U+007F (ASCII) 被编码为字节 0x00 到 0x7F (ASCII 兼容). 这意味着只包含 7 位 ASCII 字符的文件在 ASCII 和 UTF-8 两种编码方式下是一样的.
    * 所有 >U+007F 的 UCS 字符被编码为一个多个字节的串, 每个字节都有标记位集. 因此, ASCII 字节 (0x00-0x7F) 不可能作为任何其他字符的一部分.
    * 表示非 ASCII 字符的多字节串的第一个字节总是在 0xC0 到 0xFD 的范围里, 并指出这个字符包含多少个字节. 多字节串的其余字节都在 0x80 到 0xBF 范围里. 这使得重新同步非常容易, 并使编码无国界, 且很少受丢失字节的影响.
    * 可以编入所有可能的 231个 UCS 代码
    * UTF-8 编码字符理论上可以最多到 6 个字节长, 然而 16 位 BMP 字符最多只用到 3 字节长.
    * Bigendian UCS-4 字节串的排列顺序是预定的.
    * 字节 0xFE 和 0xFF 在 UTF-8 编码中从未用到.

下列字节串用来表示一个字符. 用到哪个串取决于该字符在 Unicode 中的序号.
U-00000000 - U-0000007F:     0xxxxxxx
U-00000080 - U-000007FF:     110xxxxx 10xxxxxx
U-00000800 - U-0000FFFF:     1110xxxx 10xxxxxx 10xxxxxx
U-00010000 - U-001FFFFF:     11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
U-00200000 - U-03FFFFFF:     111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
U-04000000 - U-7FFFFFFF:     1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx

xxx 的位置由字符编码数的二进制表示的位填入. 越靠右的 x 具有越少的特殊意义. 只用最短的那个足够表达一个字符编码数的多字节串. 注意在多字节串中, 第一个字节的开头"1"的数目就是整个串中字节的数目.

例如: Unicode 字符 U+00A9 = 1010 1001 (版权符号) 在 UTF-8 里的编码为:
    11000010 10101001 = 0xC2 0xA9

而字符 U+2260 = 0010 0010 0110 0000 (不等于) 编码为:
    11100010 10001001 10100000 = 0xE2 0x89 0xA0

这种编码的官方名字拼写为 UTF-8, 其中 UTF 代表 UCS Transformation Format. 请勿在任何文档中用其他名字 (比如 utf8 或 UTF_8) 来表示 UTF-8, 当然除非你指的是一个变量名而不是这种编码本身.


二 Windows环境下编码的转换

在Windows环境下,对GB2312和UTF-8编码的转换,用到如下WinAPI函数:

int WideCharToMultiByte(
    UINT CodePage, // code page
    DWORD dwFlags, // performance and mapping flags
    LPCWSTR lpWideCharStr, // wide-character string
    int cchWideChar, // number of chars in string
    LPSTR lpMultiByteStr, // buffer for new string
    int cbMultiByte, // size of buffer
    LPCSTR lpDefaultChar, // default for unmappable chars
    LPBOOL lpUsedDefaultChar // set when default char used
);

int MultiByteToWideChar(
    UINT CodePage, // code page
    DWORD dwFlags, // character-type options
    LPCSTR lpMultiByteStr, // string to map
    int cbMultiByte, // number of bytes in string
    LPWSTR lpWideCharStr, // wide-character buffer
    int cchWideChar // size of buffer
);  
   

具体转换比较简单,这里不再冗述。


二 Linux环境下编码的转换

在Linux环境下,GB2312和UTF-8编码的转换,可以直接用Linux下的iconv命令来处理。

iconv命令格式如下:

iconv -f org_coding -t dest_method org_file > new_file

在linux C库中,也有iconv函数可供程序调用。具体实现比较简单,这里也不冗述。


二 嵌入式系统的字符编码转换

在嵌入式系统中,由于资源紧张,通常字符的编码格式比较单一。如果需要对多种字符编码进行相关的转换,那么就需要自己的实际需要,来定制字库和相应的转换码表。下面例程中,中文字库大小为字符集为GB2312的范围,转换程序中,对UTF-8,也只考虑了1个byte和3个bytes的情况。这对于大部分应用来将,已经足够了。





阅读(8405) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~