Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1642341
  • 博文数量: 268
  • 博客积分: 8708
  • 博客等级: 中将
  • 技术积分: 3764
  • 用 户 组: 普通用户
  • 注册时间: 2007-04-06 15:58
文章分类

全部博文(268)

文章存档

2014年(1)

2013年(15)

2012年(23)

2011年(60)

2010年(51)

2009年(12)

2008年(59)

2007年(47)

分类:

2010-11-22 18:30:59

字符集和编码(Encoding)不同
字符集只是文字的集合,不一定适合作送、处理,有时须经编码(Encode)後才能应用。如CNS 11643和GB 2312可以使用ISO 2022、EUC等标准编码。Unicode可依不同需要以UTF-8、UTF-16、UTF-32等方法编码。有些字符集如Big5通常不须额外编码即可使用,故Big5既是字符集又是

字符集-分类

字符集通常有两种,一是专为电脑资讯处理而设,如:ASCII、Unicode、GB 2312、大五码(Big5)、CNS 11643等。一是作其他用途的,如教育用的生字表、通讯用的电报码等。

字符编码(Character encoding)是一套法则,
是指將某一字符序列對應到一指定集合中某一东西(例如可能显示为一种自然数序列,交流所用的字母表或者字音表),再將其對應到另一个给定的集合中的其它东西,如一个自然序列、8位字节或者电脉冲,以便于文本计算机中存储和通过通信网络的发送。常见的例子包括将拉丁字母表编码成摩斯电码ASCII。其中,ASCII将字母、数字和其它符号編號,並用7位元二进制來表示这个整数。通常會額外使用一个扩充的位元,以便于以8位字节的方式存储。

Unicode 的编码和实现
编码方式
与 ISO 10646 的通用字符集(Universal Character Set,UCS)概念相对应,目前实际应用的 Unicode 版本对应于 UCS-2,16位的编码空间。也就是每个字符占用2个字节。这样理论上一共最多可以表示 216 即 65536 个字符。基本满足各种语言的使用。
实现方式
Unicode 的实现方式不同于编码方式。一个字符的 Unicode 编码是确定的。但是在实际传输过程中,由于不同系统平台的设计不一定一致,以及出于节省空间的目的,对 Unicode 编码的实现方式有所不同。Unicode 的实现方式称为Unicode转换格式(Unicode Translation Format,简称为 UTF)。
例如,如果一个仅包含基本7位ASCII字符的 Unicode 文件,如果每个字符都使用2字节的原 Unicode 编码传输,其第一字节的8位始终为0。这就造成了比较大的浪费。对于这种情况,可以使用 UTF-8 编码,这是一种变长编码,它将基本7位ASCII字符仍用7位编码表示,占用一个字节(首位补0)。而遇到与其他 Unicode 字符混合的情况,将按一定算法转换,每个字符使用1-3个字节编码,并利用首位为0或1进行识别。
再如,如果直接使用与 Unicode 编码一致(仅限于 BMP 字符)的 UTF-16 编码,由于每个字符占用了两个字节,在Macintosh (Mac)机和PC机上,对字节顺序的理解是不一致的。这时同一字节流可能会被解释为不同内容,如某字符为十六进制编码4E59,按两个字节拆分为4E和59,在Mac上读取时是从低字节开始,那么在Mac OS会认为此4E59编码为594E,找到的字符为“奎”,而在Windows上从高字节开始读取,则编码为 U+4E59 的字符为“乙”。就是说在Windows下以UTF-16编码保存一个字符“乙”,在Mac OS里打开会显示成“奎”。此类情况说明UTF-16的编码顺序若不加以人为定义就可能发生混淆,于是在 UTF-16 编码实现方式中使用了大尾序(Big-Endian, 简写为UTF-16 BE)、小尾序(Little-Endian, 简写为UTF-16 LE)的概念,以及可附加的BOM(Byte Order Mark)解决方案,目前在PC机上的Windows系统和Linux系统对于UTF-16编码默认使用UTF-16 LE。

简单字符集

按照惯例,人们认为字符集和字符编码是同义词,因为使用同样的标准来定义提供什么字符并且这些字符如何编码到一系列的代码单元(通常一个字符一个单元)。由于历史的原因,MIME和使用这种编码的系统使用术语字符集来表示用于将一组字符编码成一系列八位字节数据的整个系统。

现代编码模型

它们将字符编码的概念分为:有哪些字符、它们的编号、这些编号如何编码成一系列的“码元”(有限大小的数字)以及最后这些单元如何組成八位字节流

字符集(Character Set)是一个系统支持的所有抽象字符的集合。例如拉丁、希腊和斯拉夫字母表分为字母、数字、变音符号、标点和如空格这样的一些少数特殊字符,它们都能按照一种简单的线性序列排列(尽管对它们的处理需要另外的规则,如带有变音符号的字母这样的特定序列如何解释——但这不属于字符表的范畴)。为了方便起见,这样的字符表可以包括预先编号的字母和变音符号的组合。其它的书写系统,如阿拉伯语和希伯莱语,由于要适应双向文字和在不同情形下按照不同方式交叉在一起的字形,就使用更为复杂的符号表表示。

编码字符集(CCS:Coded Character Set)定义一個非負整數為一個碼點,而其集合則表示一个字符集。例如,在一个给定的字符表中,表示大写拉丁字母“A”的字符被赋予整数65、字符“B”是66,如此继续下去。一个完整的字符集和與其对应的整数集一起被称为“编码字符集”。多个编码字符集可以表示同样的字符表,例如ISO-8859-1和IBM的代码页037和500含蓋同样的字符表但是将它们映射为不同的代码。在一个编码字符集中,每个码点仅仅表示一个字符。

字符编码表(CEF:Character Encoding Form)定义将编码字符集的整数代码转换成有限大小整数代码值以利于使用固定位的二进制表示数字的形式(比如,几乎任何的计算机系统)的系统存储。例如,使用16位单元存储数字信息的系统每个单元只能够直接表示从0到65,535的数值,但是如果使用多个16位单元就能够表示更大的整数。这就是CEF的作用:它定义一种从0到140万的范围的单个 码点映射到一些列列的范围在0到65,5356的单个或多个 码值的方法。

最简单的字符编码表就是單純地选择足够大的单位,以保证编码字符集中的所有数值能够直接编码(一个码点对应一个码值)。这对于能够用使用八位元來表示的编码字符集(如多数传统的非CJK编码所作的那样)是合理的,对于能够使用十六位元來表示的编码字符集(如早期版本的統一碼)来说也足够合理。但是,随着编码字符集的大小增加(例如,现代統一碼每个字符至少需要21位),这变得越来越没有效率,并且很难让现有系统适应更大的码值。因此,许多使用新近統一碼版本的系统或者使用将統一碼码点對應為可变长度8位字节序列的UTF-8,或者使用将码点對應为可变长16位字的UTF-16

字符编码方案(CES:Character Encoding Scheme)定义如何將整数代码對應到适合基于8位字节数据的文件系统存储或用於网络传输。在多数使用統一碼的场合,使用一个简单的字符来指定字节顺序是大端序或者小端序(即使对于UTF-8来说并不需要这些)。然而,有些复杂的字符编码机制使用转义序列在几种简单编码机制(如ISO/IEC 2022)和用于减小每个单元所用字节数的压缩机制(如SCSUBOCUPunycode)之间切换。

----------------------------------------------------------------------------------------------------------

windows编程

字符集
软件的本地化要解决的真正问题,实际上就是如何来处理不同的字符集。多年来,许多人
一直将文本串作为一系列单字节字符来进行编码,并在结尾处放上一个零。对于我们来说,这
已经成了习惯。当调用s t r l e n函数时,它在以0结尾的单字节字符数组中返回字符的数目。 
问题是,有些文字和书写规则(比如日文中的汉字就是个典型的例子)的字符集中的符号 
太多了,因此单字节(它提供的符号最多不能超过2 5 6个 2<*8)是根本不敷使用的。为此出现了双 
字节字符集(D B C S),以支持这些文字和书写规则。
 
单字节与双字节字符集 
在双字节字符集中,字符串中的每个字符可以包含一个字节或包含两个字节。例如,日文 
中的汉字,如果第一个字符在0 x 8 1与0 x 9 F之间,或者在0 x E 0与0 x F C之间,那么就必须观察下 
一个字节,才能确定字符串中的这个完整的字符。使用双字节字符集,对于程序员来说简直是 
个很大的难题,因为有些字符只有一个字节宽,而有些字符则是两个字节宽。 
如果只是调用s t r l e n函数,那么你无法真正了解字符串中究竟有多少字符,它只能告诉你 
到达结尾的0之前有多少个字节。

Unicode:宽字节字符集 
U n i c o d e提供了一种简单而又一致的表示字符串的方法。U n i c o d e字符串中的所有字符都是 
1 6位的(两个字节)。它没有专门的字节来指明下一个字节是属于同一个字符的组成部分,还 
是一个新字符。这意味着你只需要对指针进行递增或递减,就可以遍历字符串中的各个字符, 
不再需要调用C h a r N e x t、C h a r P r e v和I s D B C S L e a d B y t e之类的函数。 
由于U n i c o d e用一个1 6位的值来表示每个字符,因此总共可以得到65 000个字符,这样, 
它就能够对世界各国的书面文字中的所有字符进行编码,远远超过了单字节字符集的2 5 6个字 
符的数目。 
目前,已经为阿拉伯文、中文拼音、西里尔字母(俄文)、希腊文、西伯莱文、日文、韩 
文和拉丁文(英文)字母定义了U n i c o d e代码点 。这些字符集中还包含了大量的标点符号、 
数学符号、技术符号、箭头、装饰标志、区分标志和其他许多字符。如果将所有这些字母和符 
号加在一起,总计约达3 5 0 0 0个不同的代码点,这样,总计65 000多个代码点中,大约还有一 
半可供将来扩充时使用。 
这65 536个字符可以分成不同的区域。表2-2 显示了这样的区域的一部分以及分配给这些 
区域的字符。 
表2-2   区域字符 
1 6位代码字符 16 位代码字符 
0 0 0 0 - 0 0 7 F A S C I I 0 3 0 0 - 0 3 6 F 通用区分标志 
0 0 8 0 - 0 0 F F 拉丁文1字符 0 4 0 0 - 0 4 F F 西里尔字母 
0 1 0 0 - 0 1 7 F 欧洲拉丁文 0 5 3 0 - 0 5 8 F 亚美尼亚文 
0 1 8 0 - 0 1 F F 扩充拉丁文 0 5 9 0 - 0 5 F F 西伯莱文 
0 2 5 0 - 0 2 A F 标准拼音 0 6 0 0 - 0 6 F F 阿拉伯文 
0 2 B 0 - 0 2 F F 修改型字母 0 9 0 0 - 0 9 7 F 梵文 
目前尚未分配的代码点大约还有29 000个,不过它们是保留供将来使用的。另外,大约有 
6 0 0 0个代码点是保留供个人使用的。 

为什么使用U n i c o d e 

当开发应用程序时,当然应该考虑利用U n i c o d e的优点。即使现在你不打算对应用程序进 
行本地化,开发时将U n i c o d e放在心上,肯定可以简化将来的代码转换工作。此外,U n i c o d e还 
具备下列功能: 
• 可以很容易地在不同语言之间进行数据交换。 
• 使你能够分配支持所有语言的单个二进制. e x e文件或D L L文件。 
• 提高应用程序的运行效率为什么使用U n i c o d e 
当开发应用程序时,当然应该考虑利用U n i c o d e的优点。即使现在你不打算对应用程序进 
行本地化,开发时将U n i c o d e放在心上,肯定可以简化将来的代码转换工作。此外,U n i c o d e还 
具备下列功能: 
• 可以很容易地在不同语言之间进行数据交换。 
• 使你能够分配支持所有语言的单个二进制. e x e文件或D L L文件。 
• 提高应用程序的运行效率(本章后面还要详细介绍)。 

如何编写U n i c o d e源代码 

C运行期库对U n i c o d e的支持 
为了利用U n i c o d e字符串,定义了一些数据类型。标准的C头文件S t r i n g . h已经作了修改, 
以便定义一个名字为w c h a r _ t的数据类型,它是一个U n i c o d e字符的数据类型: 
typedef unsigned short wchar_t; 
例如,如果想要创建一个缓存,用于存放最多为9 9个字符的U n i c o d e字符串和一个结尾为 
零的字符,可以使用下面这个语句: 
wchar_t szBuffer[100];
该语句创建了一个由1 0 0个1 6位值组成的数组。当然,标准的C运行期字符串函数,如 
s t r c p y、s t r c h r和s t r c a t等,只能对A N S I字符串进行操作,不能正确地处理U n i c o d e字符串。因此, 
ANSI C也拥有一组补充函数。清单2 - 1显示了一些标准的ANSI C字符串函数,后面是它们的等 
价U n i c o d e函数。 
char *strcat(char *, const char *);
wchar_t * wcscat(wchar_t *, const wchar_t *);

注意大多数软件开发人员可能已经不记得这样一个非常重要的问题了,那就是 

M i c r o s o f t公司提供的C运行期库与A N S I的标准C运行期库是一致的。ANSI C规定,C 
运行期库支持U n i c o d e字符和字符串。这意味着始终都可以调用C运行期函数,以便对 
U n i c o d e字符和字符串进行操作,即使是在Windows 98上运行,也可以调用这些函数。 
换句话说,w c s c a t、w c s l e n和w c s t o k等函数都能够在Windows 98上很好地运行,这些 
都是必须关心的操作系统函数。 
对于包含了对s t r函数或w c s函数进行显式调用的代码来说,无法非常容易地同时为A N S I和 
U n i c o d e对这些代码进行编译。本章前面说过,可以创建同时为A N S I和U n i c o d e进行编译的单 
个源代码文件。若要建立双重功能,必须包含T C h a r. h文件,而不是包含S t r i n g . h文件。 
T C h a r. h文件的唯一作用是帮助创建A N S I / U n i c o d e通用源代码文件。它包含你应该用在源 
代码中的一组宏,而不应该直接调用s t r函数或者w c s函数。如果在编译源代码文件时定义了 
_ U N I C O D E,这些宏就会引用w c s这组函数。如果没有定义_ U N I C O D E,那么这些宏将引用s t r 
这组宏。 
例如,在T C h a r. h中有一个宏称为_ t c s c p y。如果在包含该头文件时没有定义_ U N I C O D E ,那 
么_ t c s c p y就会扩展为A N S I的s t r c p y函数。但是如果定义了_UNICODE, _tcscpy将扩展为U n i c o d e 
的w c s c p y函数。拥有字符串参数的所有C运行期函数都在T C h a r. h文件中定义了一个通用宏。如 
果使用通用宏,而不是A N S I / U n i c o d e的特定函数名,就能够顺利地创建可以为A N S I或U n i c o d e 
进行编译的源代码。

字符串(literal string)前面的大写字母L,用于告诉编译器该字符串应该作为U n i c o d e字符 

串来编译。当编译器将字符串置于程序的数据部分中时,它在每个字符之间分散插入零字节。 
这种变更带来的问题是,现在只有当定义了_ U N I C O D E时,程序才能成功地进行编译。我们需 
要另一个宏,以便有选择地在字符串的前面加上大写字母L。这项工作由_ T E X T宏来完成, 
_ T E X T宏也在T C h a r. h文件中做了定义。

成为符合A N S I和U n i c o d e的应用程序 

即使你不打算立即使用U n i c o d e,最好也应该着手将你的应用程序转换成符合U n i c o d e的应 
用程序。下面是应该遵循的一些基本原则: 
• 将文本串视为字符数组,而不是c h a r s数组或字节数组。 
• 将通用数据类型(如T C H A R和P T S T R)用于文本字符和字符串。 
• 将显式数据类型(如B Y T E和P B Y T E)用于字节、字节指针和数据缓存。 
• 将T E X T宏用于原义字符和字符串。 
• 执行全局性替换(例如用P T S T R替换P S T R)。 
• 修改字符串运算问题。例如函数通常希望你在字符中传递一个缓存的大小,而不是字节。 
这意味着你不应该传递s i z e o f ( s z B u ff e r ) ,而应该传递(s i z e o f ( s z B u ff e r ) / s i z e o f ( T C H A R )。另外, 
如果需要为字符串分配一个内存块,并且拥有该字符串中的字符数目,那么请记住要按字节来 
分配内存。这就是说,应该调用malloc(nCharacters *sizeof(TCHAR)),而不是调用m a l l o c 
( n C h a r a c t e r s )。在上面所说的所有原则中,这是最难记住的一条原则,如果操作错误,编译器 
将不发出任何警告。
 
在U n i c o d e与A N S I之间转换字符串 

Wi n d o w s函数M u l t i B y t e To Wi d e C h a r用于将多字节字符串转换成宽字符串。

一般来说,可以通过下列步骤将多字节字符串转换 

成U n i c o d e等价字符串: 
1) 调用M u l t i B y t e To Wi d e C h a r函数,为p Wi d e C h a r S t r参数传递N U L L,为c c h Wi d e C h a r参数 
传递0。 
2) 分配足够的内存块,用于存放转换后的U n i c o d e字符串。该内存块的大小由前面对 
M u l t B y t e To Wi d e C h a r的调用返回。 
3) 再次调用M u l t i B y t e To Wi d e C h a r,这次将缓存的地址作为p Wi d e C h a r S t r参数来传递,并 
传递第一次调用M u l t i B y t e To Wi d e C h a r时返回的缓存大小,作为c c h Wi d e c h a r参数。 
4. 使用转换后的字符串。 
5) 释放U n i c o d e字符串占用的内存块。 
函数Wi d e C h a r To M u l t i B y t e将宽字符串转换成等价的多字节字符串





阅读(1698) | 评论(0) | 转发(0) |
0

上一篇:Windows消息队列

下一篇:跨平台

给主人留下些什么吧!~~