Chinaunix首页 | 论坛 | 博客
  • 博客访问: 246126
  • 博文数量: 41
  • 博客积分: 928
  • 博客等级: 准尉
  • 技术积分: 550
  • 用 户 组: 普通用户
  • 注册时间: 2011-04-01 10:07
文章分类
文章存档

2011年(41)

分类: 嵌入式

2011-09-04 10:34:55


汉字编码问题(转)  摘自http://www.cnblogs.com/gaowg/articles/1101542.html

由于常常要和汉字处理打交道,因此,我常常受到汉字编码问题的困扰。在不断的打击与坚持中,也积累了一点汉字编码方面的经验,想和大家一起分享。
一、汉字编码的种类
汉字编码中现在主要用到的有三类,包括GBK,GB2312和Big5。
1、 GB2312又称国标码,由国家标准总局发布,1981年5月1日实施,通行于大陆。新加坡等地也使用此编码。它是一个简化字的编码规范,当然也包括其他 的符号、字母、日文假名等,共7445个图形字符,其中汉字占6763个。我们平时说6768个汉字,实际上里边有5个编码为空白,所以总共有6763个 汉字。
 GB2312规定“对任意一个图形字符都采用两个字节表示,每个字节均采用七位编码表示”,习惯上称第一个字节为“高字节”,第二个字 节 为“低字节”。GB2312中汉字的编码范围为,第一字节0xB0-0xF7(对应十进制为176-247),第二个字节0xA0-0xFE(对应十进制 为160-254)。
GB2312将代码表分为94个区,对应第一字节(0xa1-0xfe);每个区94个位(0xa1-0xfe),对应第 二 字节,两个字节的值分别为区号值和位号值加32(2OH),因此也称为区位码。01-09区为符号、数字区,16-87区为汉字区 (0xb0-0xf7),10-15区、88-94区是有待进一步标准化的空白区。
2、Big5又称大五码,主要为香港与台湾使用,即是一个繁体 字编码。每个汉字由两个字节构成,第一个字节的范围从0X81-0XFE(即129-255),共126种。第二个字节的范围不连续,分别为 0X40-0X7E(即64-126),0XA1-0XFE(即161-254),共157种。

3、GBK是 GB2312的扩展,是向上兼容的,因此GB2312中的汉字的编码与GBK中汉字的相 同。另外,GBK中还包含繁体字的编码,它与Big5编码之间的关系我还没有弄明白,好像是不一致的。GBK中每个汉字仍然包含两个字节,第一个字节的范 围是0x81-0xFE(即129-254),第二个字节的范围是0x40-0xFE(即64-254)。GBK中有码位23940个,包含汉字 21003个。

表1 汉字编码范围

名称    |       第一字节         |           第二字节
--------|-------------------------|------------------------
GB2312  |   0xB0-0xF7(176-247)   |    0xA0-0xFE(160-254)
--------|-------------------------|-------------------------
GBK0    |  x81-0xFE(129-254)    |  0x40-0xFE(64-254)
--------|-------------------------|-------------------------
Big5    |   0x81-0xFE(129-255)  |   0x40-0x7E(64-126),
       |                        |    0xA1-0xFE(161-254)
--------|-------------------------|------------------------


二、对汉字进行hash
为了处理汉字的方便,在查找汉字的时候,我们通常会用到hash的方法,那怎么来确定一个汉字位置呢?这就和每种编码的排列有关了,这里主要给出一种hash函数的策略。
对于GB2312编码,设输入的汉字为GBword,我们可以采用公式(C1-176)*94 + (C2-161)确定GBindex。其中,C1表示第一字节,C2表示第二字节。具体如下:
   GBindex = ((unsigned char)GBword.at(0)-176)*94 + (unsignedchar)GBword.at(1) - 161;
   之所以用unsigned char类型,是因为char是一个字节,如果用unsigendint,因为int是4个字节的,所以会造成扩展,导致错误。
      对于GBK编码,设输入的汉字为GBKword,则可以采用公式   index=(ch1-0x81)*190+(ch2-0x40)-(ch2/128),其中ch1是第一字节,ch2是第二字节。
具体的,
   GBKindex = ((unsigned char)GBKword[0]-129)*190 +
      ((unsigned char)GBKword[1]-64) - (unsignedchar)GBKword[1]/128;

三、怎样判断一个汉字的是什么编码
直接根据汉字的编码范围判断,对于GB2312和GBK可用下面两个程序实现。
1、判断是否是GB2312
bool isGBCode(const string& strIn)
{
unsigned char ch1;
unsigned char ch2;

if (strIn.size() >= 2)
{
ch1 = (unsigned char)strIn.at(0);
ch2 = (unsigned char)strIn.at(1);
if (ch1>=176 && ch1<=247 &&ch2>=160 &&ch2<=254)
return true;
else return false;
}
else return false;
}
2、判断是否是GBK编码
bool isGBKCode(const string& strIn)
{
unsigned char ch1;
unsigned char ch2;

if (strIn.size() >= 2)
{
ch1 = (unsigned char)strIn.at(0);
ch2 = (unsigned char)strIn.at(1);
if (ch1>=129 && ch1<=254 &&ch2>=64 &&ch2<=254)
return true;
else return false;
}
else return false;
}

3、对于Big5
它 的范围为:高字节从0xA0到0xFE,低字节从0x40到0x7E,和0xA1到0xFE两部分。判断一个汉字是否是 BIG5编码,可以如上对字符的编码范围判断即可。如何定位呢?那么也想象所有编码排列为一个二维坐标,纵坐标是高字节,横坐标是低字节。这样一行上的汉 字个数:(0x7E-0x40+1)+(0xFE-0xA1+1)=157。那么定位算法分两块,为:

if 0x40<=ch2<=0x7E: #is big5 char
index=((ch1-0xA1)*157+(ch2-0x40))*2
elif 0xA1<=ch2<=0xFE: #is big5 char
index=((ch1-0xA1)*157+(ch2-0xA1+63))*2

对于第二块,计算偏移量时因为有两块数值,所以在计算后面一段值时,不要忘了前面还有一段值。0x7E-0x40+1=63。

四、如果判断一个字符是西文字符还是中文字符
大家知道西文字符主要是指ASCII码,它用一个字节表示。且这个字符转换成数字之后,该数字是大于0的,而汉字是两个字节的,第一个字节的转化为数字之后应该是小于0的,因此可以根据每个字节转化为数字之后是否小于0,判断它是否是汉字。
例如,设输入字为strin,则,
    If (strin.at(0) < 0)
      cout << ”是汉字” << endl;
    else cout << ”不是汉字” << endl;
五、下载GBK编码表(见附件)
   下载GB2312编码表见下面的回帖


--------------------------------------------------------------------------------
  另一些与编码相关的文章:
1、GB码和BIG5码的互换技术
-------------------------------------------------------------------------
中文与英文用ASCII码一个字节表示不同,它使用两个字节来表示。事实上,在文本文件中保存的就是每个汉字对应的两个字节编码,而显示问题由中文操作系统自动解决。
   汉字编码并不统一,我们使用的是GB码,而台湾地区使用的是BIG5码。BIG5码文件中保存的是汉字相应的BIG5编码,GB码文件中保存的是汉字相应的GB编码。所以转换工作的关键是有一个记录每个BIG5编码对应GB编码的码表文件。
   GB码编码规则是这样的:每个汉字由两个字节构成,第一个字节的范围从0XA1-0XFE,共96种。第二个字节的范围分别为0XA1-0XFE,共96种。利用这两个字节共可定义出 96 * 96=8836种汉字。实际共有6763个汉字。
   BIG5码编码规则是这样的:每个汉字由两个字节构成,第一个字节的范围从0X81-0XFE,共126种。第二个字节的范围分别为 0X40-0X7E,0XA1-0XFE,共157种。也就是说,利用这两个字节共可定义出 126 * 157=19782种汉字。这些汉字的一部分是我们常用到的,如一、丁,这些字我们称为常用字,其BIG5码的范围为0XA440-0XC671,共 5401个。较不常用的字,如滥、调,我们称为次常用字,范围为 0XC940-0XF9FE,共7652个,剩下的便是一些特殊字符。
   制作码表文件的原理是这样的:首先将所有的GB编码写入一个文件,然后,使用具有GB码到BIG5码转换功能的软件,如UCDOS下的CONVERT.EXE,将文件转换为BIG5码文件,即得到码表文件。
   下面的程序可将全部国标码写入文件gb.txt(以下全部程序用foxpro书写,可很容易的转换成其他语言)
   fp = fopen("gb.txt",2)
   for i=161 to 247
     for j=161 to 254
       =fwrite(fp,chr(i)+chr(j))
     next
     =fwrite(fp,chr(13)+chr(10))
   next
   =fwrite(fp,chr(26))
   =fclose(fp)

   文件的组织形式:行对应编码的第一字节,列对应编码的第二字节。使用时请注意编码的偏移量,如汉字“啊”GB编码0xb1a1第一字节0xb1(177) 第二字节0xa1(161)所以他应该在文件的第(177-161=16)行第((161-161)*2=0)列。
   运行CONVERT.EXE将gb.txt转换成BIG5码的文件,这样就可得到按GB码组织的BIG5码表文件big5.txt。反之亦可得到按BIG5码组织的GB码表文件。

   转换的思路是这样的:(用foxpro书写)
   首先将码表文件装入数组
   fp = fopen("big5.txt")
   i = 0
   do while feof(fp)
     i = i+1
     dime dict
     dict = fgets(fp)
   enddo
   =fclose(fp)
   其次将待转换的文本装入变量
   create cursor temp (mm m)
   append blank
   append memo mm from textfilename
   text = mm
   然后扫描文本,替换所有的GB编码
   temp = ""
   i = 1
   do while i < len(text)
     ch = substr(text,i,1)
     if isascii(ch)   && 若是ASCII码
       temp = temp+ch
       i = i+1
     else
       ch1 = substr(text,i+1,1)
       big5 =substr(dict[asc(ch)-161+1],(asc(ch1)-161)*2+1,2)
       temp = temp+big5
       i = i+2
     endif
   enddo
   最后将在temp中得到转换后的文本

   需要注意的是,在foxpro中数组指针是以1开始,substr函数的起始位>=1。

--------------------------------------------------------------------------------
  一、GB2312-80介绍
GB2312码是中华人民共和国国家汉字信息交换用编码,全称《信息交换用汉字编码字符集--基本集》,由国家标准总局发布,1981年5月1日实施,通行于大陆。新加坡等地也使用此编码。
GB2312 收录简化汉字及符号、字母、日文假名等共7445个图形字符,其中汉字占6763个。GB2312规定“对任意一个图形字符都采用两个字节表示,每个字节 均采用七位编码表示”,习惯上称第一个字节为“高字节”,第二个字节为“低字节”。GB2312-80包含了大部分常用的一、二级汉字,和9区的符号。该 字符集是几乎所有的中文系统和国际化的软件都支持的中文字符集,这也是最基本的中文字符集。其编码范围是高位0xa1-0xfe,低位也是 0xa1-0xfe;汉字从0xb0a1开始,结束于0xf7fe。
GB2312将代码表分为94个区,对应第一字节(0xa1-0xfe);每 个区94个位(0xa1-0xfe),对应第二字节,两个字节的值分别为区号值和位号值加32(2OH),因此也称为区位码。01-09区为符号、数字 区,16-87区为汉字区(0xb0-0xf7),10-15区、88-94区是有待进一步标准化的空白区。GB2312将收录的汉字分成两级:第一级是 常用汉字计3755个,置于16-55区,按汉语拼音字母/笔形顺序排列;第二级汉字是次常用汉字计3008个,置于56-87区,按部首/笔画顺序排 列。故而GB2312最多能表示6763个汉字。
GB2312的编码范围为2121H-777EH,与ASCII有重叠,通行方法是将GB码两个字节的最高位置1以示区别。
二、GB2312-80的扩展

GBK是GB2312-80的扩展,是向上兼容的。它包含了20902个汉字,其编码范围是0x8140-0xfefe,剔除高位0x80的字位。其所有字符都可以一对一映射到Unicode2.0。
GB18030-2000(GBK2K)在GBK的基础上进一步扩展了汉字,增加了藏、蒙等少数民族的字形。GBK2K从根本上解决了字位不够,字形不足的问题。它有几个特点:
?它并没有确定所有的字形,只是规定了编码范围,留待以后扩充。
?编码是变长的,其二字节部分与GBK兼容;四字节部分是扩充的字形、字位,其编码范围是首字节0x81-0xfe、二字节0x30-0x39、三字节0x81-0xfe、四字节0x30-0x39。
?它的推广是分阶段的,首先要求实现的是能够完全映射到Unicode3.0标准的所有字形。
?它是国家标准,是强制性的。
?现在还没有任何一个操作系统或软件实现了GBK2K的支持,这是现阶段和将来汉化的工作内容。

三、Unicode编码

国 际标准组织于1984年4月成立ISO/IECJTC1/SC2/WG2工作组,针对各国文字、符号进行统一性编码。1991年美国跨国公司成立 UnicodeConsortium,并于1991年10月与WG2达成协议,采用同一编码字集。目前Unicode是采用16位编码体系,其字符集内容 与ISO10646的BMP(BasicMultilingualPlane)相同。Unicode于1992年6月通过 DIS(DrafInternationalStandard),目前版本V2.0于1996公布,内容包含符号6811个,汉字20902个,韩文拼音 11172个,造字区6400个,保留20249个,共计65534个。
随着国际互联网的迅速发展,要求进行数据交换的需求越来越大,不同的编码体系越来越成为信息交换的障碍,而且多种语言共存的文档不断增多,单靠代码页已很难解决这些问题,于是UNICODE应运而生。
UNICODE 有双重含义,首先UNICODE是对国际标准ISO/IEC10646编码的一种称谓(ISO/IEC10646是一个国际标准,亦称大字符集,它是 ISO于1993年颁布的一项重要国际标准,其宗旨是全球所有文种统一编码),另外它又是由美国的HP、Microsoft、IBM、Apple等大企业 组成的联盟集团的名称,成立该集团的宗旨就是要推进多文种的统一编码。
UNICODE同现在流行的代码页最显著不同点在于:UNICODE是两 字 节的全编码,对于ASCII字符它也使用两字节表示。代码页是通过高字节的取值范围来确定是ASCII字符,还是汉字的高字节。如果发生数据损坏,某处内 容破坏,则会引起其后汉字的混乱。UNICODE则一律使用两个字节表示一个字符,最明显的好处是它简化了汉字的处理过程。
UNICODE使用平面来描述编码空间,每个平面分为256行,256列,相对于两字节编码的高低两个字节。
UNICODE的第一个平面,称为BasicMultilingualPlane(基本多文种平面),简称BMP,由于BMP仅用两个字节表示,所以倍受青睐。


--------------------------------------------------------------------------------
  相关附件: (共 31517 字节)

[这个贴子最后由taozi在 2005/12/06 04:24pm 第 2 次编辑]

一些相关的网页:
GBK代码表:
GBK 汉字内码扩展规范:
下载GB2312编码表,见附件
 

--------------------------------------------------------------------------------
  谈谈Unicode编码,简要解释UCS、UTF、BMP、BOM等名词
这是一篇程序员写给程序员的趣味读物。所谓趣味是指可以比较轻松地了解一些原来不清楚的概念,增进知识,类似于打RPG游戏的升级。整理这篇文章的动机是两个问题:
问题一:
使用Windows记事本的“另存为”,可以在GBK、Unicode、Unicode big endian和UTF-8这几种编码方式间相互转换。同样是txt文件,Windows是怎样识别编码方式的呢?

我 很早前就发现Unicode、Unicode big endian和UTF-8编码的txt文件的开头会多出几个字节,分别是FF、FE(Unicode),FE、FF(Unicode big endian),EF、BB、BF(UTF-8)。但这些标记是基于什么标准呢?

问题二:
最近在网上 看到一个ConvertUTF.c,实现了UTF-32、UTF-16和UTF-8这三种编码方式的相互转换。对于 Unicode(UCS2)、GBK、UTF-8这些编码方式,我原来就了解。但这个程序让我有些糊涂,想不起来UTF-16和UCS2有什么关系。
查了查相关资料,总算将这些问题弄清楚了,顺带也了解了一些Unicode的细节。写成一篇文章,送给有过类似疑问的朋友。本文在写作时尽量做到通俗易懂,但要求读者知道什么是字节,什么是十六进制。

0、big endian和little endian
big endian和little endian是CPU处理多字节数的不同方式。例如“汉”字的Unicode编码是6C49。那么写到文件里时,究竟是将6C写在前面,还是将49写在前 面?如果将6C写在前面,就是big endian。如果将49写在前面,就是little endian。

“endian”这个词出自《格列佛游记》。小人国的内战就源于吃鸡蛋时是究竟从大头(Big-Endian)敲开还是从小头(Little-Endian)敲开,由此曾发生过六次叛乱,一个皇帝送了命,另一个丢了王位。

我们一般将endian翻译成“字节序”,将big endian和little endian称作“大尾”和“小尾”。

1、字符编码、内码,顺带介绍汉字编码
字符必须编码后才能被计算机处理。计算机使用的缺省编码方式就是计算机的内码。早期的计算机使用7位的ASCII编码,为了处理汉字,程序员设计了用于简体中文的GB2312和用于繁体中文的big5。

GB2312(1980年)一共收录了7445个字符,包括6763个汉字和682个其它符号。汉字区的内码范围高字节从B0-F7,低字节从A1-FE,占用的码位是72*94=6768。其中有5个空位是D7FA-D7FE。

GB2312支持的汉字太少。1995年的汉字扩展规范GBK1.0收录了21886个符号,它分为汉字区和图形符号区。汉字区包括21003个字符。

从 ASCII、GB2312到GBK,这些编码方法是向下兼容的,即同一个字符在这些方案中总是有相同的编码,后面的标准支持更多的字符。在这些编 码中,英文和中文可以统一地处理。区分中文编码的方法是高字节的最高位不为0。按照程序员的称呼,GB2312、GBK都属于双字节字符集(DBCS)。

2000 年的GB18030是取代GBK1.0的正式国家标准。该标准收录了27484个汉字,同时还收录了藏文、蒙文、维吾尔文等主要的少数民族 文字。从汉字字汇上说,GB18030在GB13000.1的20902个汉字的基础上增加了CJK扩展A的6582个汉字(Unicode码 0x3400-0x4db5),一共收录了27484个汉字。

CJK就是中日韩的意思。Unicode为了节省码位,将中日韩三国语言中的文字统一编码。GB13000.1就是ISO/IEC 10646-1的中文版,相当于Unicode 1.1。

GB18030 的编码采用单字节、双字节和4字节方案。其中单字节、双字节和GBK是完全兼容的。4字节编码的码位就是收录了CJK扩展A的 6582个汉字。 例如:UCS的0x3400在GB18030中的编码应该是8139EF30,UCS的0x3401在GB18030中的编码应该是8139EF31。

微软提供了GB18030的升级包,但这个升级包只是提供了一套支持CJK扩展A的6582个汉字的新字体:新宋体-18030,并不改变内码。Windows 的内码仍然是GBK。

这里还有一些细节:

GB2312的原文还是区位码,从区位码到内码,需要在高字节和低字节上分别加上A0。

对 于任何字符编码,编码单元的顺序是由编码方案指定的,与endian无关。例如GBK的编码单元是字节,用两个字节表示一个汉字。 这两个字节的顺序是固定的,不受CPU字节序的影响。UTF-16的编码单元是word(双字节),word之间的顺序是编码方案指定的,word内部的 字节排列才会受到endian的影响。后面还会介绍UTF-16。

GB2312的两个字节的最高位都是1。但 符合这个条件的码位只有128*128=16384个。所以GBK和GB18030的低字节最高位都可能 不是1。不过这不影响DBCS字符流的解析:在读取DBCS字符流时,只要遇到高位为1的字节,就可以将下两个字节作为一个双字节编码,而不用管低字节的 高位是什么。

2、Unicode、UCS和UTF
前面提到从ASCII、GB2312、GBK到GB18030的编码方法是向下兼容的。而Unicode只与ASCII兼容(更准确地说,是与ISO-8859-1兼容),与GB码不兼容。例如“汉”字的Unicode编码是6C49,而GB码是BABA。

Unicode 也是一种字符编码方法,不过它是由国际组织设计,可以容纳全世界所有语言文字的编码方案。Unicode的学名 是"UniversalMultiple-Octet Coded Character Set",简称为UCS。UCS可以看作是"Unicode Character Set"的缩写。

根据维基百科全书( /wiki/)的记载:历史上存在两个试图独立设计Unicode的组织,即国 际标准化组织(ISO)和一个软件制造商的协会(unicode.org)。ISO开发了ISO 10646项目,Unicode协会开发了Unicode项目。

在1991年前后,双方都认识到世界不需要两个不兼容的字符集。于是它们开始合并双方的工作成果,并为创立一个单一编码表而协同工作。从Unicode2.0开始,Unicode项目采用了与ISO 10646-1相同的字库和字码。

目前两个项目仍都存在,并独立地公布各自的标准。Unicode协会现在的最新版本是2005年的Unicode 4.1.0。ISO的最新标准是ISO10646-3:2003。

UCS 只是规定如何编码,并没有规定如何传输、保存这个编码。例如“汉”字的UCS编码是6C49,我可以用4个ascii数字来传输、保存这个编 码;也可以用utf-8编码:3个连续的字节E6 B1 89来表示它。关键在于通信双方都要认可。UTF-8、UTF-7、UTF-16都是被广泛接受的方案。UTF-8的一个特别的好处是它与ISO- 8859-1完全兼容。UTF是“UCS Transformation format”的缩写。

IETF的 RFC2781和RFC3629以RFC的一贯风格,清晰、明快又不失严谨地描述了UTF-16和UTF-8的编码方法。我总是记不得 IETF是Internet Engineering Task Force的缩写。但IETF负责维护的RFC是Internet上一切规范的基础。

2.1、内码和code page
目前Windows的内核已经支持Unicode字符集,这样在内核上可以支持全世界所有的语言文字。但是由于现有的大量程序和文档都采用了某种特定语言的编码,例如GBK,Windows不可能不支持现有的编码,而全部改用Unicode。

Windows使用代码页(code page)来适应各个国家和地区。code page可以被理解为前面提到的内码。GBK对应的code page是CP936。

微软也为GB18030定义了code page:CP54936。但是由于GB18030有一部分4字节编码,而Windows的代码页只支持单字节和双字节编码,所以这个code page是无法真正使用的。

3、UCS-2、UCS-4、BMP
UCS有两种格式:UCS-2和UCS-4。顾名思义,UCS-2就是用两个字节编码,UCS-4就是用4个字节(实际上只用了31位,最高位必须为0)编码。下面让我们做一些简单的数学游戏:

UCS-2有2^16=65536个码位,UCS-4有2^31=2147483648个码位。

UCS- 4根据最高位为0的最高字节分成2^7=128个group。每个group再根据次高字节分为256个plane。每个plane根据第 3个字节分为256行 (rows),每行包含256个cells。当然同一行的cells只是最后一个字节不同,其余都相同。

group 0的plane 0被称作Basic Multilingual Plane, 即BMP。或者说UCS-4中,高两个字节为0的码位被称作BMP。

将UCS-4的BMP去掉前面的两个零字节就得到了UCS-2。在UCS-2的两个字节前加上两个零字节,就得到了UCS-4的BMP。而目前的UCS-4规范中还没有任何字符被分配在BMP之外。

4、UTF编码

UTF-8就是以8位为单元对UCS进行编码。从UCS-2到UTF-8的编码方式如下:

UCS-2编码(16进制) UTF-8 字节流(二进制)
0000 - 007F 0xxxxxxx
0080 - 07FF 110xxxxx 10xxxxxx
0800 - FFFF 1110xxxx 10xxxxxx 10xxxxxx

例 如“汉”字的Unicode编码是6C49。6C49在0800-FFFF之间,所以肯定要用3字节模板了:1110xxxx10xxxxxx 10xxxxxx。将6C49写成二进制是:0110 110001 001001, 用这个比特流依次代替模板中的x,得到:1110011010110001 10001001,即E6 B1 89。

读者可以用记事本测试一下我们的编码是否正确。需要注意,UltraEdit在打开utf-8编码的文本文件时会自动转换为UTF-16,可能产生混淆。你可以在设置中关掉这个选项。更好的工具是Hex Workshop。

UTF- 16以16位为单元对UCS进行编码。对于小于0x10000的UCS码,UTF-16编码就等于UCS码对应的16位无符号整数。对于不 小于0x10000的UCS码,定义了一个算法。不过由于实际使用的UCS2,或者UCS4的BMP必然小于0x10000,所以就目前而言,可以认为 UTF-16和UCS-2基本相同。但UCS-2只是一个编码方案,UTF-16却要用于实际的传输,所以就不得不考虑字节序的问题。

5、UTF的字节序和BOM
UTF- 8以字节为编码单元,没有字节序的问题。UTF-16以两个字节为编码单元,在解释一个UTF-16文 本前,首先要弄清楚每个编码单元的字节序。例如“奎”的Unicode编码是594E,“乙”的Unicode编码是4E59。如果我们收到UTF-16 字节流“594E”,那么这是“奎”还是“乙”?

Unicode规范中推荐的标记字节顺序的方法是BOM。BOM不是“Bill OfMaterial”的BOM表,而是Byte Order Mark。BOM是一个有点小聪明的想法:

在 UCS编码中有一个叫做"ZERO WIDTH NO-BREAKSPACE"的字符,它的编码是FEFF。而FFFE在UCS中是不存在的字符,所以不应该出现在实际传输中。UCS规范建议我们在传输 字节流前,先传输 字符"ZERO WIDTH NO-BREAK SPACE"。

这样如果接收者收到FEFF,就表明这个字节流是Big-Endian的;如果收到FFFE,就表明这个字节流是Little-Endian的。因此字符"ZERO WIDTH NO-BREAK SPACE"又被称作BOM。

UTF- 8不需要BOM来表明字节顺序,但可以用BOM来表明编码方式。字符"ZEROWIDTH NO-BREAK SPACE"的UTF-8编码是EF BB BF(读者可以用我们前面介绍的编码方法验证一下)。所以如果接收者收到以EF BB BF开头的字节流,就知道这是UTF-8编码了。

Windows就是使用BOM来标记文本文件的编码方式的。

6、进一步的参考资料
本文主要参考的资料是 "Short overview of ISO-IEC 10646 andUnicode" ()。

我还找了两篇看上去不错的资料,不过因为我开始的疑问都找到了答案,所以就没有看:

"Understanding Unicode A general introduction to the UnicodeStandard" ()
"Character set encoding basics Understanding character set encodings andlegacy encodings"()
我写过UTF-8、UCS-2、GBK相互转换的软件包,包括使用WindowsAPI和不使用Windows API的版本。以后有时间的话,我会整理一下放到我的个人主页上()。

我是想清楚所有问题后才开始写这篇文章的,原以为一会儿就能写好。没想到考虑措辞和查证细节花费了很长时间,竟然从下午1:30写到9:00。希望有读者能从中受益。

附录1 再说说区位码、GB2312、内码和代码页
有的朋友对文章中这句话还有疑问:
“GB2312的原文还是区位码,从区位码到内码,需要在高字节和低字节上分别加上A0。”

我再详细解释一下:

“GB2312 的原文”是指国家1980年的一个标准《中华人民共和国国家标准 信息交换用汉字编码字符集 基本集 GB 2312-80》。这个标准用两个数来编码汉字和中文符号。第一个数称为“区”,第二个数称为“位”。所以也称为区位码。1-9区是中文符号,16-55 区是一级汉字,56-87区是二级汉字。现在Windows也还有区位输入法,例如输入1601得到“啊”。(这个区位输入法可以自动识别16进制的 GB2312和10进制的区位码,也就是说输入B0A1同样会得到“啊”。)

内码是指操作系统内部的字符编码。早期操作系统的内码是与语言相关的。现在的Windows在系统内部支持Unicode,然后用代码页适应各种语言,“内码”的概念就比较模糊了。微软一般将缺省代码页指定的编码说成是内码。

内码这个词汇,并没有什么官方的定义,代码页也只是微软这个公司的叫法。作为程序员,我们只要知道它们是什么东西,没有必要过多地考证这些名词。

所谓代码页(code page)就是针对一种语言文字的字符编码。例如GBK的code page是CP936,BIG5的code page是CP950,GB2312的code page是CP20936。

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兼容,就不会出现乱码了。

再 说区位码,啊的区位码是1601,写成16进制是0x10,0x01。这和计算机广泛使用的ASCII编码冲突。为了兼容00-7f的ASCII 编码,我们在区位码的高、低字节上分别加上A0。这样“啊”的编码就成为B0A1。我们将加过两个A0的编码也称为GB2312编码,虽然GB2312的 原文根本没提到这一点。


--------------------------------------------------------------------------------
  一、几个基本概念
  1、bit 与  byte
  bite 是二进制的即0和1,译作比特。
  Byte是指八个bit,代表一个Ansi或Ascii 代码,即一个英文字母,译作字节。由于汉字使用了16位(比特)代码,所以称为双字节。
  其换算关系很简单,一byte等于八bit。
  2,ANSI码,ANSI是(AmericanNational Standard Institude)的简写。ANCII是American Standard Code for Information Interchange的简写。
   ANSI是以标准的八位来显示一个字符的,可以代表256字。基本上包括了拉丁语系中所需要的全部字符。起初美国人认为7位(比特)就足够了,因为2的 7次方等于128,而英文字母只有26个,大小写加一起52个,再加上十个数字,几个标点和数学运算符号,也够了。所以就制定了ANCII七位的代码系 统,这七位的代码系统的128位与ANSI的256中的前128完全一致,加之现在的计算机系统都能自动分别,所以,这两个概念也就不太分别了。
  二、GB 2312 汉字编码字符集
GB2312 码是中华人民共和国国家标准汉字信息交换用编码,全称《信息交换用汉字编码字符集?基本集》,标准号为GB 2312—80(GB是“国标”二字的汉语拼音缩写),由国家标准总局发布,1981年5月1 日实施。习惯上称国标码、GB码,或区位码。它是一个简化字汉字的编码,通行于中国大陆地区。新加坡等地也使用这一编码。
  GB 2312—80收录简化汉字及一般符号、序号、数字、拉丁字母、日文假名、希腊字母、俄文字母、汉语拼音符号、汉语注音字母,共7445个图形字符。其中 汉字以外的图形字符682个,汉字6763个。由于6763比那GB 2312-80要好记得多,尤其是在GBK也流行的时代,人们总是习惯用6763来代指那通行(同时也让我们痛苦了)若干年的字符系统。
  GB 2312-80规定,“对任意一个图形字符都采用两个字节(Byte)表示。每个字节均采用GB 1988-80及GB 2311-80中的七位编码表示。两个字节中前面的字节为第一字节,后面的字节为第二字节。”习惯上称第一字节为“高字节”(Upper),第二字节为 “低字节”(low)。
  GB 2312-80将代码分为94个区(Section),对应第一字节,每个区94个位(Position),对应第二字节。两个字节的值,分别为区号值和位号值各加32(20H)。我们通常所说的区位便由此而来。
   GB 2312-80规定,01~09区(原规定为1~9区,为表示区位码方便起见,现改称01~09区)为符号、数字区,16~87区为汉字区。而10~15 区、88~94区是有待于“进一步标准化”的“空白位置”区域。便第10区推荐与第3区的94个图形字符(即GB1988-80中的94个图形字符)相 同,字形宽度为其宽度的一半。)
  GB 2312-80把收录的汉字分成两级。第一级汉字是常用汉字,计3755个,置于16~55区,按汉语拼音字母/笔形顺序排列;第二级汉字是次常用汉字, 计3008个,置于56~87区,按部首/笔区顺序排列。字音以普通话审音委员会发表的《普通话导读词三次审音总表初稿》(1963年出版)为准,字形以 中华人民共和国文化部、中国文字改革委员会公布的《印刷通用汉字字形表》(1964年出版)为准。
  例:汉字“啊”,第一字节为0110000,第二字节为0100001,即16区、01位,用16。
这 些字的来源我不知道是根据什么,但就我处理文献的情况看,有些是对很常用的字,如用于人名的“璟”字,一是明代著名戏曲理论家“沈璟”,一是南唐中主(同 时又是文学家)“李璟”,出现频率比较高,但却没有收在6763之中,而象“芏”“塄”“蓥”等近千字几乎用不上的字却占据着极紧张的资源。
  以后的GBK更有这种情况。
  三、GB/T12345 汉字编码字符集
  GB/T12345和GB2312一样,是中华人民共和国国家标准汉字信息交换用编码,全称《信息交换用汉字编码字符集辅助集》,标准号为GB/T12345-90,中华人民共和国国家技术监督局1990年6月13日发布,1990年12月1日实施。
   GB/T12345-90是一个关于繁体汉字的编码标准。所谓“辅助集”,?是与“基本集”(GB2312-80)相对应而言。即:GB/T12345 是“与GB2312相对应的图形字符集。原则上,本字符集是将GB2312中的简化字用相应的繁体字替换而成。因此,这些替代的繁体字具有与被替代的简化 字相同的编码;未曾简化的汉字以及非汉字图形字符,仍是GB2312中的汉字及图形字符,并具有与之相同编码。”
  关于繁体字替换简化字的原 则,GB/T12345注明:“本标准原则是按照《简化字总表》中所列繁体字与简化字的对应关系进行替换。”《简化字总表》由中国文字改革委员会1964 年5月发表,后经国家语言文字工作委员会作个别修订,国务院1986年6月4日批准重新发表。
  除了以上的根本差异外,GB/T12345与GB2312的区别还有以下几点:1,增补了个别图形字符,共收录7583个图形字符:汉字以外的图形字符716个,汉字6866个(其中一级汉字3755个,二级汉字3008个,增补汉字103个。)
  a,“根据排版需要,增补了竖排标点符号29个,这些字符增补于6区57位至85位。”
  b,“根据GB5007.1(《信息交换用汉字24×24点阵字模集》),增加了6个汉语拼音用图形字符,这些字符增补于8区27位至32位。”
   c,“GB2312中,由于60年代汉字简化被精简的字有103个,这些被精简的字根据繁体字处理系统的需要增补于88~89区。”所谓精简,即废除某 个繁体字,而用另一个字代替,如废除“雲”字,而以“云”字代替。由此形成一个简化字对应两个或两个以上繁体字的现象。
  2,GB/T12345规定的在七位环境中指明图形字符集的转义序列不同,同时规定了在八位环境中的转义序列。
   GB/T12345没有指明其字符集字形依据,便它使用的繁体汉字,与《简化字总表》中所使用的字形一致。其绝大多数汉字,使用了“新字形”。例如, “产”的繁体字,它使用了新字形“產”,而不自旧字形“產”。因此,一些旧字形与新字形的差异,被视为字形的差异(异体字),而不是繁体与简体的差异。 如:收录“奂”“换”“唤”,而不用“奐”“換”“喚”,即因为“奐”是旧字形,而非繁体字。但是其中极个别字又使用了旧字形,如“为”“伪”的繁体字, 使用了旧字形“爲”“僞”,而上用新字形“為”“偽”。关于新旧字形,可参见中国社会科学院语言研究所编纂的《现代汉语词典》(商务印书馆1978年第一 版)、《新华字典》(商务印书馆1979年修订版)所附的《新旧字形对照表》,以及辞海编辑委员会编纂的《辞海》(上海辞书出版社1979年出版)所附的 《新旧字形对照举例》。
关于被精简的汉字:
  1,88~89区所列的103个汉字,GB/T12345称为“60年代汉字简化时被精 简 的字。”,这一表达不完全准确。例如:,“丰”与“豐”,汉字简化时精简了“豐”字,以“丰”字替代,而GB/T12345将被精简的“豐”字,作为 “丰”的繁体,置于23~65,而将“丰”字置于88~19。类似的情况占其103字的三分之一左右。
  2,所谓103个“被精简的汉字”, 只 是被精简的“繁体字”,而未包括被精简(废除)的“异体字”。例如,“昇”和“陞”,作为“升”的异体字,被停止使用,GB/T12345亦未收录。相关 的法定文件为中华人民共和国文化部、中国文字改革委员会1955年6月发布的《第一批异体字整理表》,该表列出异体字810组,1865字,并规定废除异 体字1055个。一些异体字,习惯上也被看作是简化字,所以,《简化字总表》特地从《第一批异体字整理表》中选出39个异体字,列为附录。
   3,按照汉字简化原则,在容易引起歧义时不简化。例如“余”和“餘”,《简化字总表》对“餘”字的脚注说;“在余和餘意义可能混淆时,仍用餘,如文言句 “餘年无多”。同时,有些汉字只简化其字义的某一个或几个义项,如徵,在象徵等义项上被简化为征,而在音乐调值的义项上(即宫商角徵羽的徵,读作 zhi[止]),并不简化。因此在GB2312中,保留了个别繁体(或异体)字,也就是说,同时收录了一个字的简体和繁体(或异体),这包括“干乾、后 後、伙夥、么麽、于於、余餘、折摺、征徵”等。作为与GB2312对应的繁体编码,GB/T12345在这些字上处理较混乱。例如:GB/T12345将 “伙”置于27-79,“夥”置于66-23,与GB2312編碼相同,即,以“伙”對應“伙”,以“夥”對應“夥”。另一種情況是,GB/T12345 將“後”置于26-83,对应GB2312的“后”,将“後”置于65-65,对应GB2312的“後”;将“徵”置于53-87,对应GB2312的 “征”,将“征”置于65-71,对应GB2312的“徵”,显然不当。
  注:
  1,以上代码表,除06、08区增补符号用GIF图形编制外,其他均使用GBK代码编制,只有在你的电脑能完全正确GBK汉字时,才能保证看到的上表与GB/T12345标准印刷件(中国标准出版社1991年10月版)相同的字形。
   2,尽管满足查看GBK汉字的条件,仍有两个汉字的显示,与GB/T12345标准印刷件有所差异。两个字的代码为47-22、80-89。第一字的印 刷件字形,未列入有关简化字的法定文件,但习惯上被视为“隙”的繁体,而GBK编码未收录此字,无法显示,故以“隙”替代。第二字的印刷件字形,系对应简 体“瘞”,按照《简化字总表》第二表《可作简化偏旁的简化字和简化偏旁》,“夾”简化为“夹”,所以,“瘗”对应的繁体字,应该是“瘗”,同时,印刷件上 的此字不见于字书,因此它可能是排版时错误,故上表使用了“瘗”字。
  3,01~15区的符号和空白位置,除增补者以外,与GB2312的符号、编码位置完全相同。
 
--------------------------------------------------------------------------------
  四、BIG-5字符集
  BIG-5码是通行于台湾、香港地区的一个繁体字编码方案,俗称“大五码”。它并不是一个法定的编码方案,存在着一些瑕疵,业界的评价也不高,但它广泛地被应用于电脑业,尤其是在国际互联网中,从而成为一种事实上的行业标准。
  关于BIG-5码的背景,一直未见详细记载,简单介绍如下:
   1983年10月,**家科学委员会、教育部汉字推行委员会、中央标准局、行政院主计处电子资料处理中心共同制定了《通用汉字标准交换码》 (chinese  Ideographic standard  code for  information  interchange ,简称CISCII码),经试用修订,1986年8月4日由台湾中央标准局公布为法定标准,标准编号为CNS 11643。这一标准于1992年5月21日重新修订公布,更名为《中文标准交换码》(chinese standard  interchange  code).1995mm 1 月4日,台湾中央标准局又公布了CNS 11643-1《中文标准交换码使用方法》。
  BIG-5码是1984年台湾信息工业促进会根据《通用汉字标准交换码》制订的编码方案。至于为何称为“BIG-5”。
  BIG-5码是一个双字节编码方案,其第一字节的值在16进制的AO~FE之间,第二字节在40~7E和A1~FE之间。因此,其第一字节的最高位是1,第二字节的最高位则可能是1,也可能是0。
BIG-5码的图形符号及汉字,基本与CNS 11643标准的第一、第二字面(Plane)一致,它收录13461个符号和汉字,包括:
  1,符号408个,编码位置为A140~A3FE(实际止于A3BF,末尾有空白位置。)
  2,汉字13053个,分为常用字和次常用字两部分,各部分中的汉字按笔划/部首排列。其中:
  a,常用字5401个,编码位置为A440~C67E。包括台湾教育部颁布的《常用汉字标准字体表》中的全部汉字4808个,**中国小教科书常用字587个,异体字6个。
B,次常用字7652个,编码位置为C940~F9FE(实际止于F9D5,末尾有空白位置)。包括台湾教育部《次常用汉字标准字体表》的全部汉字6341个,《罕用汉字标准字体表》中使用频率较高的字1311个。
  其余的A040~A0FE、C6A1`FEFE为空白区域。一些空白位置,经常被用于用户造字区,而且多存放香港常用字和粤语方言字。
   现在流行的BIG-5码字库,在F9D6~F9DC位置大都有7个常用字,据说为倚天系统所增。若计此7字,则全数为13060个汉字,13468个汉 字和符号。此外,一些BIG-5码字库,如Windows繁体中文版的True Type细明体(华康科技提供,2.0版),在F9DD~F9FE位置还有33个制表符和1个“■”符号。
  五,BIG5+码
  1,编订BIG5+码之缘起
台湾行政院协助解决众多使用BIG5码政府单位于进行公文电子传递时寓到自造字无法转换CNS问题,而于数次会商后决议成立专案委托中文电脑基金会办理[BIG5码字集扩编计划],86年7月扩编完成。
  2,编码原则
BIG5+ 码系以CNS为蓝本,共增编标准字集4760个字符与推荐字集3250个字符;其标准字集即纳编CNS第3字面字集内之4145个,第4个字面字集内之 219个字,均为一般文书常用之中文字,如推广应用于研究发新版中文软体,则估计可解决80%的BIG5自造字转换CNS交换码问题。
(一),长度仍为双字节,即高字节之第一位元(MSB)=1。
(二),保留原有之标准字集字区及使用者加字区,使与原有系统具相容性。
(三),以国家标准(CNS11643)及国际标准(ISO10646)字集为字源范围,并依CNS之序编入。
(四)包含于ISO10646或CNS11643字集内且市面已广为使用之倚天自造字及符号,编入标准字集并保留原码位。
(五),单独成字之部首不再重覆编码(如金、木、水、火、土)。
(六),有重复的字删除其后者,错字则依CNS修正之。
  3,字码架构
(一),总码位:由原有之19782个扩大为23940个(高字节为81-FE,低位元组为40-7E、80-FE)。
(二)编码区间
   a,第一标准字集:此区即原BIG-5码标准字集但删除22个重字,编码范围为A140-F9FE(高字节为A1-F9,低字节为40-7E、A1- FE)。共有13973个字符,包括常用汉字5401个(A440-C67E),次常用汉字7693个(C940-F9D5)及符号471个(A140- A3FE)、字符408个(C6A1-C8FE)。
  b,第二标准字集:此区即扩编部分,编码范围为8180-FEA0(高字节为81-F9,低字节为80-A0)。共收编罕用汉字4158个。
   c,CMEX推荐字集:因BIG-5码系统之编码位置有限,未能编入第一及第二标准字集之较常用罕用及异体汉字、简体字与日韩汉字3454个,经中推会 (CMEX)建议集中收编于此区。编码范围为原造字区之8140-83FE、8E40-A0FE(高字节为81-83、8E-A0,低字节为40—7E、 A1-FE)。
  d,造字区:仅使用第二标准字集时,仍保留5809个码位供使用者造字,可编码区间不变;但同时使用推荐字集时,因 BIG5+ 码之推荐字集系使用原造字区之8140-83FE及8E40-A0FE,供造字之码位仅余2355个,可编码区间为FA40-FEFE(785个码位)、 8440-8DFE(1570个码位)。
  e,使用者专用字集:为使各行业专用之字集亦能进行信息交换,向中推会申请登记ID后,将ID字形等依照 输规定传出供对方显示或列印。
  使用者专用字集之编码区与CMEX推荐字集相同,亦使用到原造字区。
  4,可用之工具
(一),24*24点阵字形档。
(二),注音符号、仓颉码属性档。
(三),CNS11643、ISO10646码对照档。
(四),BIG5+〈——〉ISO10646转码程序。
(五),BIG5+〈——〉CNS11643转码程序。
(六)BIG-5码自造字转BIG-5码管理程序。
(七)BIG-5自造字转码程序。
  5,使用方法
  因BIG5+码在标准字集外尚提供推荐字集,各单位可依自己原有造字情况选择适当之使用方法:
  (一)字集之使用1.以下情可使用全字集(即第一、第二标准字集及推荐字集,共21585个字符)
(1),全无自造字者。
(2),原来已有自造字,其编码区间未与推荐字集重叠者,(即FA40—FEFE及8440-8DFE以外)
(3),原来已有自造初开球编码区间虽与推荐字集重叠,但可全部转换为新码者。
(4),原来已有自造字,但经转换为新码后剩余自造字未超过2355个,且可以或原意改置于FA40-FEFE及8440-8DFE以外者。2.以下情况仅使用标准字集(即第一与二标准字集,共13461个字符):
(1),有自造字,但转码后剩余自造字仍超过2355个者。
(2),原有自造字耸部或部分落于FA40-8440-8DFE两个造字区(推荐字集使用范围)内,不易或不愿转换为新码者。
(二)字形转输与交换规格之使用
BIG- 5码虽已扩编,但其余未能纳入自造字及未来不断新增之自造字,依旧会产生交换及传送问题;为使这些自造字于网路传输及档案交换时,仍可作字形显示与列印, 特订定以下几项规格:1,文件档案交换传输规格,依SGML(ISO8879)格式及CNS(ISO9541)字形资讯交换规格,订定SGML文件档案内 字形应含之参数。2,中文周边装置字形下载规格:包括中文终端机、打印机及其他终端设备,系依CNS13479(ISO6429)规范订定字形下载之规 格。
(三)用户需准备之工作
BIG-5码编扩编后纳入之自造字,如不作转码,将来交换时一定会发生一字两码的问题,因此在BIG5+码 之 新版中文系统软体推出前,用户必需先转换现在自造字之旧码,其程序如下:1,建立自造字之旧码与扩编后新码对照表:各单位之造字区管理者可利用第六项工具 [BIG5自造字转标准字对照表管理程式]比对造字区内自造字后建立单位内新/旧码对照表。2,清查需要转码之资料档:各单位或集中或各自处理,均必需先 清查所有用过原造字区字码之料档,以备进行转码。3,自造字旧码之转换:各项业务负责人或各使用者可利用第七项工具[BIG5自造字转标准字转换程式]及 所建立之单位内新/旧码对照表,将所有的[文字档(.txt。)原用之自编旧码转换为BIG5+新码。4,单位内造字区之重整;为避免转码后发生一字两码 之现象,各单位原有之造字区应作整理,删除已编入BIG5+码系统者,其余自造字则保留原编码或重新编码(重整造字区)。
6,应用现况
台湾厂商如:芙蓉坊、昌泰科枝、大同、倚天等公司已将BIG5+码应用于新产品中。

六、台湾制定的CNS11643
  1,编订中文标准交换码之缘起
   72年10月由台湾科学委员会、教育部、中央标准局及本中心 合编[通用汉字标准交换码]后决议试用二年;试用期满,经检讨修正重编并向中央标准局申请订为国家标准,75年8月4日获该局审定公布国家标准,编号 [CNS11643];81年51 21日再由该局因应实际需要修订扩编,并更名为[中文标准交换码(chinesestandard interchange code)]。
  2,CNS11643之适用范围
  本标准适用于中文信息之处理。
  3,编码之各项考虑
  中文信息标准交换码是否能普遍地推广使用,使一般使用者共同乐意接受,端视其是否具有实用性,因此本码之编码原则研订时,曾先就标准码的结构、编码需求等作多方面的周密考虑。
  (一),以教育部所公布的四个字体表之字集为范围。
  (二),根据使用的频率及范围,整理后分别编排于各个字面,以适应各个层次之使用者。
  (三),符合国际信息传输上所使用之CNS5205[信息处理及交换用七位码字符集]及CNS7654[信息处理-七位及八位码字符集-延码技术]标准通信定则。
  (四)涵盖常用之外语字母及工商界与学校所使用之文字及符号。
  4,字集编排原则
  (一),中文标准交换码分为十六个字面,每个字面可陈列94列*94行,即8836个字符。目前第一至第七字面列有字集,第八至第十一字面预留扩编之用;第十二至第十六字面则为使用者加字区,凡未收于本码系统之中文及符号,他用者可视需要自行编订于加字区使用。
  总支持文字量达141376个。
   (二)各字面字集排列大抵依使用频率为次序,每一字面以常用字为主,第二字面以次常用字为主,第三字面以部分罕用字及较常用异体字为主,第四字面以 ISODIS10646第二版之汉字、各单位/信息业用字及户政用字为主,第五字面以罕用字为主,第六、第七字面以异体字为主。其中第一第二字面字集先于 民国七十五年八月四日公布为国家标准。
  5,字码编排原则
  (一),文字之选择及字体悉依教育部[汉字标准字体表]为基准。说明: 中 国文字的困扰主要有两方面,一是文字的数量太大,二是异体字繁多。实际上一般人常用的不过七千字左右,新字又不断的增加,造成中文资料处理上的困难;而教 育部的标准字体表之字集系经多年之搜集、考证、分析、选取,为较不偏颇,最具客观性之用字字集,应能符合一般使用者之需求。
  (二),以2个字节(bytes)为中文码编码单位,并以十六进位制之文数字表示之。说明:[以2个字节为字码单位,于处理时可增加信息传输之速度],符合一般资料处理作业之需要。采用十六进位制数字编码,系因应资料处理人员惯用之进位法,用以表示两字节最为简明。
   (三)符合CNS5205及CNS7654之通信定则。说明:本编码为符合CNS5305及CNS7654通信定则之规定,所有控制码均予避开,即字码 中之00至20以及7F均予避开,则7BIT字码集共有94个编码位置,两个字节革命可编8836个中文字码,订为一字面。
  (四),依字之使用频率而编排于各不同字面。说明:在做信息传输时,若欲传送出现在不同字面上的字,必须先送出转字面控制码。为提高传输效率,常会一起出现的字编在同一字面中,可减低字面转换的次数。
  (五),使先笔画后部首的排列顺序来编订字码。说明:每一字面均按文字灭口笔画数为首序编订字码,使用者以笔画数即可查寻字码。
  六、字集之说明
  第一字面:本编码系统为减少字面转换次数,特编最常用之中文字及符号、字母、部首等于第一字面;所编字汇及码区分别说明如下:
  1,符号区
  符号区之编码位置规划于第一字面之2121至427E,有3102个编码位置,目前暂编符号684个,所余空位供尔后增添之用。
  已编入之特殊符号及文字类别如下:
  (1),间隔符号1个。
  (2),标点符号28个。
  (3)括号及制表符号89个。
  (4),一般符号34个。
  (5)、学术符号51个。
  (6)、单位符号31个。
  (7)数字符号42个,包括阿拉伯数字10个,罗马数字大小写共20个,中国数字12个。
  (8)外文字母100个,包括大写英文字母,小字英文字母各26个,大写希腊字母、小写希腊字母各24个。
  (9)汉字注音符号42个。

  (10)数字序列符号20个。
  (11)中国文字部首213个(夕,夕两部首同归于夕部首中,夕部首得于将来扩编时一并列入增订。)
  (12)控制码符号33个。
  2 中文字区
   CNS第一字面之中文字区编码区间由4421至7D4B,所编字汇5401字,除包括教育部颁订之“常用汉字标准字体表”所列全部4808字外,并优收 编国中、国小教科书中常用字587字及异体字6字。第二字面:本字集所编字汇7650字,除教育部所颁“次常用汉字标准字体表”外,并筛选编入罕用字表中 使用频率较高之1320字。字码区间为2121至7244。第三字面:本字集即77年6月行政院主计处电子处理资料中心为搜集仍涵盖教育部罕用及异体字表 中之较常用字,所编订之使用者加字区第14字面字集第一部分,字数6148字;原码序不变,字码区间仍为2121至6246。第四字面:本字集所编字汇 7298字,除包括原第14字面第二部分171字外,并搜集户役政及其他使用单位,ISO10646第2版汉字集、信息业次常用字而成,字码区间为 2121至6E5C。第五字面:本字集所编字汇共8603个字,系未包含于前4个字面之教育部罕用字。字码区间为2121至7C51。第六字面:本字集所 编字汇共6388个字,为不包含于前5个字面且笔画在14画(含)以下之教育部异体字。字码区间为2121至647A。第七字面:本字集所编字汇6539 个字,为不包含前6个字面之教育部异体字,字码区间为2121为6655。使用者得视自己的需求参考本标准之字集、字序编订内码表。
  七,CNS11643之使用
   (一)字面之指定与转换依据CNS7654(78年7月15日版)第5。3。9节之规定,中文码可置于多字节符号字库(MULTIPLE BYTE GRAPHIC  REPERTOIRE)中,经由ESC2/4 2/9 F四个字节之逸出顺序码指定于G1字集,或经由ESC2/4 2/10 F指定于G2字集,亦可经由ESC2/4 2/11 F指定于G3字集,其中F 可用3/0~3/15来指定相对之一至十六中文字面;至于英文之字集则可经由ESC2/8 F 指定于G0字面。在7个位元的环境下,对于各种字面的使用说明如下:1,利用SI使用G0字面,并为锁定方式。       2,利用SO使用G1字面, 并为锁定方式。3,利用LS2使用G2字面,并为锁定方式。4,利用LS3使用G3字面,并为锁定方式。5,利用SS2使用 G2字面,并为非锁定方式。6,利用       SS3使用G3字面,并为非锁定方式。
  为求使用方便,终端设备在开机时可将G0、G1、G2等三个字集分别设定为ASCII、第一字面及第二字面,将G3字集设定为其他较常用的字面。有关这些控制码的使用,请参考CNS7654        。
  (二)使用者加字区之使用:
  为适应各种不同性质之中文资料处理作业,CNS11643特别订定自第十二字面起为使用者加字区;尚未收编于本系统之中文字或符号。由使用者视需要先编于此区内使用;字面之指定与转换方法与前七个字面相同。
  八,CNS11643之推广应用
   本交换码系统依国家标准法之规定,系由经济部中央标准局负责检讨增修之,但该局为加强推广该标准之应用,特将此系统及中文字型档委托本中心代为办理推广 应用事宜;本中心为顾及标准字型档之完整性,以利此标准之推广,另再商得内政部及经济部工业局同意一并提供其他字型档。
  CNS11643目前之应用情形如下:
  (一)台湾之应用情形
  1,公文电子交换之标准传递码,行政院“政府机关公文电子传递作业”决定,凡是经“交换中心”(交通部管资中心)之公文,一律须先转换为CNS后再传递。
  2,EUC码援用CNS之字集及架构:UNIX系统上使用之EUC虽为4BYTE之内码,但却全部采用CNS之编码架构及字集;其2个低字节之HIGH均OFF后字码即与CNS完全相同,因此不需再以对照表方式转换;亦可视为CNS应用于内码之实例。
  3,BIG5+码之字源:86年7月完成之“BIG5+”(即BIG-5码之扩编)系以CNS11643为蓝本,纳编CNS第3字面之4,145个、第4字面之219个一般文书常用之中文字。
  (二)国外之应用情形
   ISO10646及UNICODE汉字均收编CNS字集:ISO10646及UNICODE目前共收编20902个汉字,其中17011个字系来自 CNS(第1第2字面及第3字面3895个,第4字面56个),现又增编CNS的5881个字。因此,不便台湾标准得与国际标准相容,国内电脑业者在国际 市场之竞争力得以增强,将来ISO10646及UNICODE发展成熟后,使用者亦可得以顺利转换。
  七,CCCII编码
   CCCII编码是CHINESECHARACTER CODE FOR INformATION INTERCHANGE 的缩写,是经台湾中研院中美会及国科会等单位支持,于1979年12月25日集合由台湾图书馆学者,文字学家及电脑专家组成“汉字整理小组”提出的汉字编 码,已广泛用于港台图书馆及与美国网上数字化图书信息中心OCLC系统。该编写系统提供了94面(PLANE)×行(ROW)×94列 (CELL)=830584字符空间;其中每六个面构成一个层(LAYER)提供6×94×94=53016编码空间,(最后一层只有四个面)。各层定义 的汉字情况如下:
  第1层,符号和繁体汉字。
  第2层,大陆的简体汉字。
  第3-12层,汉字异体字。
  第13层,日本汉字。
  第14层,朝鲜汉字。
  第15层,保留字。
  第16层,杂项字(日本与朝鲜)
  第一至十二层的编码的编码存在关联含义,就是说同样的码在这些不同的层表示同一个汉字的不同变形。如第一层表示繁体字,第二层表示大陆简体字(如果有的话),第三至十二层表示其他的异体字,例如以下这个字的三种变形,编码的第二三字节是相同的:
  字形类型编码点,层字样
  繁体字  OX224E411
  简体字  OX284E412
  异体字  OX2E4E413
   第一层所定义的字符集如下:第1面/第2行56数学符号第1面/第3行ASCII第1面/第11行35中文标点符号第1面/第12-14行214康熙字 典偏旁部首第1面/第15行41中文数字,37拼音符号,4音调符号第1面/第16-67行4808备用字,字码213021-21637E第1面/第 68行-第3面/第64行17032备用字,字码216421-23607E20583罕用字,字码为236121-262543第3面/第65行含教育 部颁定之罕用字汇12924字,次常用字汇314字,第6面/第5行以及康煕字典、中文大辞典、财税资料考核中心字汇、电信传输码字汇、五大专题码字汇, 与其他信息字汇7345字。
  第二层收异体字共11517字,其中包含大陆简体字3625字,其它简体字7892字所有各层的第一行均为保留行,共收字53940个。
   四交大资料-BBS95年1月中国文字资料库(CCDB)字型集的应用(1)中国文字资料库(CCDB)字型集的应用(2)中国文字资料库(CCDB) 字型集的应用(3)中国文字资料库(CCDB)属性档介绍。三,ANSIZ39.64-1989 THIS NATIONALSTANDARD IS DESIGNATED as ANSIZ39.64-1989 and named “EAST ASIAN CHARACTER CODE”(EACC),but wasorigianlly known as REACC (RLIN EAST ASIAN CHARACTER CODE), THAT IS BEFORE ITBECAME A NATIONAL STANDARD RLIN STANDS FOR “RESEARCH LIBRARIES INformATIONNETWORK “ which was developed by the
 B ,浏览器:IE4。01(或更高的版本)中文版,或NETSGAPENAVIGATOR 3。X
 2,其他语种的WINDOWSS 95(或更高的版本)+微软简体中文支持或外挂中文平台。一般情况下,使用外挂中文平台时,需要将当前环境设置成为GBK码,并关闭汉字自动识别的功能。而且,许多外挂中文平台不支持全部GBK汉字。
 3,已知的常见错误。
 A,IE4。0无法显示GBK/4 AB-AF、F9-FD以及FE 中 FE40-FE4F各位置的汉字。
 B,在简体WINDOWS95环境下,NETSGAPE NAVIGATOR4。X 无法显示GBK/3中XXA0位置的汉字,A040-AOFE位置显示错误。
 C,在繁体WINDOWS95环境下,NETSGAPE NAVIGATOR4。X不能正确显示GBK/3-GBK/5之间的字符。
 GBK代表码(按分类顺序排列)
 GBK/1:GB2312非汉字符号A1-A9
 B0-B7B8-BF C0-C7C8-CF D0-D7
 GBK/2:GB2312汉字
 D8-DFE0-E7E8-EFF0-F7
 81-8384-87 88-8B8C-8F 90-93
 GBK/3:扩充汉字
 94-9798-9B 9C-A0
 AA-AFB0-B7B8-BFC0-C7C8-CF
 GBK/4:扩充汉字
 D0-D7D8-DFE0-E7E8-EFF0-F7
 F8-FE
 GBK/5:扩充非汉字
 A8-A9
 (1)AA-AF  (2)F8-FE
 用户自定义区
 (3)A1-A7

 --------------------------------------------------------------------------------
  九、ISO10646及UNICODE
  一,字码架构
  ISO10646 及UNICODE均为多汉字文内码系统
  ISO10646之汉字码长度:4 BYTE
  UNICODE 之汉字码长度:2 BYTE
  新版UNICODE 之汉字码长度:2-4 BYTE
  二,与CNS11643之关系字集相容但字序不同
  ISO10646及UNICODE之汉字集目前共收编20901个汉字,其中17011个系来自CNS字集(包括第1第2字面字集全部及第3字面字集3895字,第4字面字集56字),现已增编CNS的5881个字。
  UNICODE即所谓的“统一码”,在16位的范围内,将世界各国的文字都放在同一平面上,这样就不会出现某一位置在这种语中是这个字,在那种语言版本中是另一个字。
  11,GB13000。1收入的31个IBM OS/2专用符号。
  二,码位亦采用双字节表示,总体编码范围为8140-FEFE,首字节在81-FE之间,尾字节在40-FE之间,剔除XX7F一条线。总计23940个码位,共收入21886个汉字和图形符号,其中汉字(包括部首和构件)21003个,图形符号883个。
  全部编码分为三大部分:
  三,字形
  GBK对字形作为如下规定
  1,原则上与GB13001。1G列(即源自中国大陆法定标准的汉字)下的字形/笔画保持一致。
  2,在CJK汉字认同规则的总框架内,对所有的GBK编码汉字实施“无重正形”(“GB化”);即在不造成重码的前提下,尽量采用中国新字形。
  3,对于超出CJK汉字认同规则的,或认同规则尚未明确规定的汉字,在GBK码位上暂安放旧字形。这样,在许多情况下,GBK收入了同一汉字的新旧两种字形。
  4,非汉字符号的字形,凡GB2312已经包括的,与GB2312保持一致,超出GB2312的部分,与GB13000。保持一致。
  5,带声调的拼音字母取半角形式。
  四,目前应用
   在基本事件环境方面,微软公司自WINDOWS95简体中文版始,系统采用GBK代码,它包括了TRUETYPE宋体、黑体两种GBK字库(北京中易电 子公司提供),可以用于显示和打印,并提供了四种GBK汉字输入法。此外,浏览器IE4。0简体,繁体中文版内提供了一个GBK-BIG5代码双向转换的 功能。
  微软公司为INTERNET EXPLORER 提供的语言包中,简体中文支持(SIMPLIFIED CHINESE LANGUAGE SUPORT KIT)的两种字库宋体、黑体,也是GBK汉字(珠海四通电脑排版系统开发公司提供),其他一些中文字库生产厂商,也开始提供TRUE TYPE 或 POSTSCRIPT GBK字库。
  许多外挂式的中文平台,如南极星、四通利方(RICHWIN)等,提供GBK码的支持,包括字库、输入法和GBK与其他中文代码的转换器。
  在互联网方面,许多网站的网页使用了GBK代码,如《人民日报》等。
   但是,多数搜索引擎,都不能很好的支持GBK汉字的搜索。大陆地区的搜索引擎,有些能够不完善地支持GBK汉字检索,比如,检索GBK汉字“鎔”,只有 在网易等极个别的两三个搜索引擎中查能,而检索“朱鎔基”三个字,则能在搜索客(CSEEK)、天网等更多的几个搜索引擎中查到。而港台和国外的搜索引 擎,基至是知名的,具有简体中文查询能力的搜索引擎,如YAHOO!、OPENFIND、 ALTAVISTA等,都不支持GBK搜索。
  其他应用方面,微软公司的OFFICE 95简体中文版以上版本,提供GBK码的检索和排序。(按笔画和拼音两种方式)
  五,显示GBK码表的要求
  1,在满足下列环境要求时,才能保证全部字符显示准确,否则可能会出现缺字、显示错误或乱码。
  A ,基础环境,WINDOW9X简体中文版,或WINDOWS95繁体中文版(或更高的版本)+微软简体中文支持。
 

另一个

一、汉字编码的种类

    汉字编码中现在主要用到的有三类,包括GBK,GB2312和Big5。

    1、 GB2312又称国标码,由国家标准总局发布,1981年5月1日实施,通行于大陆。新加坡等地也使用此编码。它是一个简化字的编码规范,当然也包括其他 的符号、字母、日文假名等,共7445个图形字符,其中汉字占6763个。我们平时说6768个汉字,实际上里边有5个编码为空白,所以总共有6763个 汉字。

       GB2312规定“对任意一个图形字符都采用两个字节表示,每个字节均采用七位编码表示”,习惯上称第一个字节 为 “高字节”,第二个字节为“低字节”。GB2312中汉字的编码范围为,第一字节0xB0-0xF7(对应十进制为176-247),第二个字节 0xA0-0xFE(对应十进制为160-254)。

       GB2312将代码表分为94个区,对应第一字节 (0xa1-0xfe);每个区94个位(0xa1-0xfe),对应第二字节,两个字节的值分别为区号值和位号值加32(2OH),因此也称为区位码。 01-09区为符号、数字区,16-87区为汉字区(0xb0-0xf7),10-15区、88-94区是有待进一步标准化的空白区。

    2、 Big5又称大五码,主要为香港与台湾使用,即是一个繁体字编码。每个汉字由两个字节构成,第一个字节的范围从0X81-0XFE(即129-255), 共126种。第二个字节的范围不连续,分别为0X40-0X7E(即64-126),0XA1-0XFE(即161-254),共157种。

    3、 GBK是GB2312的扩展,是向上兼容的,因此GB2312中的汉字的编码与GBK中汉字的相同。另外,GBK中还包含繁体字的编码,它与Big5编码 之间的关系我还没有弄明白,?孟袷遣灰恢碌摹?GBK中每个汉字仍然包含两个字节,第一个字节的范围是0x81-0xFE(即129-254),第二个字 节的范围是0x40-0xFE(即64-254)。GBK中有码位23940个,包含汉字21003 个。                          

                                   表1 汉字编码范围

                    名称    第一字节              第二字节
 
                    GB2312  0xB0-0xF7(176-247)    0xA0-0xFE(160-254)
 
                    GBK     0x81-0xFE(129-254)    0x40-0xFE(64-254)
 
                    Big5    0x81-0xFE(129-255)    0x40-0x7E(64-126)

                                                  0xA1-0xFE(161-254)
 

 

二、对汉字进行hash

    为了处理汉字的方便,在查找汉字的时候,我们通常会用到hash的方法,那怎么来确定一个汉字位置呢?这就和每种编码的排列有关了,这里主要给出一种hash函数的策略。

    对于GB2312编码,设输入的汉字为GBword,我们可以采用公式(C1-176)*94 + (C2-161)确定GBindex。其中,C1表示第一字节,C2表示第二字节。具体如下:

    GBindex = ((unsigned char)GBword.at(0)-176)*94 + (unsigned char)GBword.at(1) - 161;

    之所以用unsigned char类型,是因为char是一个字节.

    对于GBK编码,设输入的汉字为GBKword,则可以采用公式   index=(ch1-0x81)*190+(ch2-0x40)-(ch2/128),其中ch1是第一字节,ch2是第二字节。

    具体的,

    GBKindex = ((unsigned char)GBKword[0] - 129) * 190 + ((unsigned char)GBKword[1] - 64) - (unsigned char)GBKword[1] / 128;

三、怎样判断一个汉字的是什么编码

    1、判断是否是GB2312

    bool isGBCode(const string& strIn)

    {

        unsigned char ch1;

        unsigned char ch2;

        if (strIn.size() >= 2)
        {

            ch1 = (unsigned char)strIn.at(0);

            ch2 = (unsigned char)strIn.at(1);

            if (ch1>=176 && ch1<=247 && ch2>=160 && ch2<=254)

                return true;

            else return false;
        }

        else return false;

    }

    2、判断是否是GBK编码

    bool isGBKCode(const string& strIn)

    {

        unsigned char ch1;

        unsigned char ch2;

        if (strIn.size() >= 2)

        {

            ch1 = (unsigned char)strIn.at(0);

            ch2 = (unsigned char)strIn.at(1);

            if (ch1>=129 && ch1<=254 && ch2>=64 && ch2<=254)

                return true;

            else return false;

        }

        else return false;

    }

    3、对于Big5

        它 的范围为:高字节从0xA0到0xFE,低字节从0x40到0x7E,和0xA1到0xFE两部分。判断一个汉字是否是BIG5编码,可以如上对字符的编 码范围判断即可。如何定位呢?那么也想象所有编码排列为一个二维坐标,纵坐标是高字节,横坐标是低字节。这样一行上的汉字个数:(0x7E- 0x40+1)+(0xFE-0xA1+1)=157。那么定位算法分两块,为:  

        if 0x40<=ch2<=0x7E: #is big5 char 

        index=((ch1-0xA1)*157+(ch2-0x40))*2 

        elif 0xA1<=ch2<=0xFE: #is big5 char 

        index=((ch1-0xA1)*157+(ch2-0xA1+63))*2 

四、如果判断一个字符是西文字符还是中文字符

    大家知道西文字符主要是指ASCII码,它用一个字节表示。且这个字符转换成数字之后,该数字是大于0的,而汉字是两个字节的,第一个字节的转化为数字之后应该是小于0的,因此可以根据每个字节转化为数字之后是否小于0,判断它是否是汉字。

    例如,设输入字为strin,则,

    If (strin.at(0) < 0)

        cout << "是汉字" << endl;

     else

        cout << "不是汉字" << endl;

     补充:

     1.汉字外部码

     汉字外部码又称为汉字输入码,是指从键盘上输入汉字时采用的编码。汉字输入编码有很多种,目前广泛使用的输入码为:

     ① 国标区位码

     ② 以汉字读音为基础的拼音码,如全拼输入法、双拼输入法、词汇输入法、智能ABC输入法等;

     ③ 以汉字字形为基础的拼形码,如五笔字型输入法;

     不同的汉字输入方法有不同的外码,但内码只能有一个。好的输入方法应具备规则简单、操作方便、容易记忆、重码率低、速度快等特点。

     2.汉字国标码

     GB2312-80编码简称国标码。由于汉字数量大,无法用一个字节进行编码,因此使用两个字节对汉字进行编码。规定两个字节的最高位用来区分ASCII码。这样国标码用两个字节的低7位对汉字进行编码。

     一 个字节只能有128-34=94种状态用于汉字编码(34是指34种控制字符),两个字节可以表示94×94=8836种状态。在基本集中汉字是按规则排 列成94行和94列的矩阵,形成汉字编码表,其行号称为区号,列号称为位号,第一个字节表示汉字在国标字符集中的区号,第二个字节表示汉字在国标字符集中 的位号。每一个汉字在94×94的矩阵中都有一个固定的区号和位号。

     例如:汉字“大”的区号为20,位号为83,即“大”的区位码为2083。

     国标码是以十六进制数字编码,编码范围是从2121H(21H即为十进制的33)到7F7FH(7FH即为十进制的127)。

     因此,国标码=区位码(用十六进制表示)+2020H。

     3.汉字机内码

     机内码是指一个汉字被计算机内部系统进行存储、处理和传输时而使用的编码。为了保证中西文兼容,同时又能区分ASCII码和汉字,因此,机内码就是将国标码的两个字节的最高位置为“1”。

     所以,机内码=国标码+8080H=区位码(用十六进制表示)+A0A0H 。

     4.汉字字形码

     字形码又称汉字字模,用于汉字的输出。汉字的字形通常采用点阵的方式产生。汉字点阵有16×16点阵、32×32点阵、64×64点阵,点阵不同,汉字字形码的长度也不同。点阵数越大,字形质量越高,字形码占用的字节数越多。

     如图1.1是“国”字24×24的点阵字形。深色小正方形可以表示一个二进制位的信息“1”,浅色小正方形表示二进制位的信息“0”。

     汉字字形码又称为汉字输出码或汉字发生器的编码。

     例:按32×32点阵存放两级汉字的汉字库,大约需要占用多少字节?

     解:32×32×6763÷8=865664B≈845KB

     大约需要845KB。

 

 


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