文字编码

在介绍文字编码之前,先来熟悉几个概念:

字符和字符集:这个很容易理解,就不多解释了。需要强调一点的是字符和字符集本身是不需要什么编码的。比如在没有计算机之前,我们照样可以说法,照样可以在纸上写各种各样的文字,这些都是不需要什么编码的。
字符编码:编码是指把字符转换为数字形式以在计算机中存储和使用的过程。从编程的角度将就是将字符转换为一个或多个字节来标示。 同样,解码就是将一个或多个字节组装为字符的过程。强调三点,编码是为了计算机的使用的; 二是编码都是数字的 ; 三是对同一个字符,可能存在好几种不同的编码
代码页:代码页规定了一个字符集中所有字符的数字编码
代码页转换表:在Windows中,默认采用Unicode编码。所以,当windows下的显示软件来显示文本信息时,需要调用windows API的相关函数来,从文件中取出一串字节串,这些字节串是按某种编码格式编码的,然后windows需要把这些转换为unicode的编码并最终显示在显示器上。因此,各种非unicode的编码需要有一个方案来转换为对应的unicode编码,这就是代码页转换表。
ANSI: American National Stands Institute。美国国家标准协会。是ISO委员会的成员。
字符编码的兼容性:是指同一字符,在两种不同的编码方案中,编码是一样的。从ASCII、GB2312到GBK,这些编码方法是向下兼容的,即同一个字符在这些方案中总是有相同的编码,后面的标准支持更多的字符。 GBK和Unicode编码是不兼容的。但是可以根据一定的规则转换
UCS只是规定如何编码,并没有规定如何传输、保存这个编码。例如“汉”字的UCS编码是6C49,我可以用4个ascii数字来传输、保存这个编码;也可以用utf-8编码:3个连续的字节E6 B1 89来表示它。关键在于通信双方都要认可。UTF-8、UTF-7、UTF-16都是被广泛接受的方案。UTF-8的一个特别的好处是它与ISO-8859-1完全兼容(ASCII)。UTF是“UCS Transformation Format”的缩写。
Unicode 是 Universal Multiple-Octet Coded Character Set 的缩写。
UCS 是 Universal Character Set(通用字符集)的缩写,即某一个整数表示哪个文字。
UTF 全称是“UCS Transformation Format”,表示文件存储和数据传输时的具体格式,比如 95 这个数字,是用一个字节来存还是用两个字节来存,还是四个字节?
UTF-8 用一个或多个字节存储一个整数。
UTF-16 始终用两个字节存储一个整数。
UTF-32 始终用四个字节存储一个整数。
UTF的依据还是UCS的编码,只是在其基础上转化。
文字的显示

1.1 发生了什么?
我们首先以Windows为例来看看文字显示过程中发生了什么。用记事本打开一个文本文件,可以看到文件包含的文字

1

下面是用WinHex打开的其在ANSI,Unicode,Unicode Big End, UTF-8编码下的字节内容:

1

我们看到:ANSI格式编码的文件有10个字节,依次是“D7 D6 B7 FB BA CD B1 E0 C2 EB”,这就是记事本从文件中读到的内容。即文件中存储的是一串字节流
记事本是用来打开文本文件的,所以它会调用Windows的文本显示函数将读到的数据作为文本显示。Windows首先将文本数据转换到它内部使用的编码格式:Unicode,然后按照文本的Unicode去字体文件中查找字体图像,最后将图像显示到窗口上。
总结一下前面的分析,文字的显示应该是这样的:
步骤1:文字首先以某种编码保存在文件中。
步骤2:Windows将文件中的文字编码映射到Unicode。
步骤3:Windows按照Unicode在字体文件中查找字体图像,画到窗口上。

所谓编码就是用数字表示字符,例如用D7D6表示“字”。当然,编码还意味着约定,即大家都认可。从《谈谈Unicode编码》中,我们知道Unicode也是一种文字编码,它的特殊性在于它是由国际组织设计,可以容纳全世界所有语言文字。而我们平常使用的文字编码通常是针对一个区域的语言、文字设计,只支持特定的语言文字。

如果上述3个步骤中任何一步发生了错误,文字就不能被正确显示,例如:
错误1:如果弄错了编码,例如将Big5编码的文字当作GBK编码,就会出现乱码。

1

错误2:如果从特定编码到Unicode的映射发生错误,例如文本数据中出现该编码方案未定义的字符,Windows就会使用缺省字符,通常是?。

1

错误3:如果当前字体不支持要显示的字符,Windows就会显示字体文件中的缺省图像:空白或方格。

在Unicode被广泛使用前,有多少种语言、文字,就可能有多少种文字编码方案。一种文字也可能有多种编码方案。那么我们怎么确定文本数据采用了什么编码?

1.2 采用了哪种编码?
按照惯例,文本文件中的数据都是文本编码,那么它怎么表明自己的编码格式?在记事本的“打开”对话框上

 

1

我们可以看到记事本支持4种编码格式:ANSI、Unicode、Unicode big endian、UTF-8。其实它们更准确的名称应该是UTF-16LE(Little Endian)、UTF-16BE(Big Endian)和UTF-8,它们是基于Unicode的不同编码方案。

Windows通过在文本文件开头增加一些特殊字节(BOM)来区分上述3种编码,并将没有BOM的文本数据按照ANSI代码页处理。那么什么是代码页,什么是ANSI代码页?

2 代码页和字符集

2.1代码页
代码页(Code Page)是个古老的专业术语,据说是IBM公司首先使用的。代码页和字符集的含义基本相同,代码页规定了适用于特定地区的字符集合,和这些字符的编码。可以将代码页理解为字符和字节数据的映射表。
Windows为自己支持的代码页都编了一个号码。例如代码页936就是简体中文 GBK,代码页950就是繁体中文 Big5。代码页的概念比较简单,就是一个字符编码方案。但要说清楚Windows的ANSI代码页,就要从Windows的区域(Locale)说起了。

2.2 区域和ANSI代码页

微软为了适应世界上不同地区用户的文化背景和生活习惯,在Windows中设计了区域(Locale)设置的功能。Local是指特定于某个国家或地区的一组设定,包括代码页,数字、货币、时间和日期的格式等。在Windows内部,其实有两个Locale设置:系统Locale和用户Locale。系统Locale决定代码页,用户Locale决定数字、货币、时间和日期的格式。我们可以在控制面板的“区域和语言选项”中设置系统Locale和用户Locale:

1

每个Locale都有一个对应的代码页。系统Locale对应的代码页被作为Windows的默认代码页。在没有文本编码信息时,Windows按照默认代码页的编码方案解释文本数据。这个默认代码页通常被称作ANSI代码页(ACP)。
ANSI代码页还有一层意思,就是微软自己定义的代码页。在历史上,IBM的个人计算机和微软公司的操作系统曾经是PC的标准配置。微软公司将IBM公司定义的代码页称作OEM代码页,在IBM公司的代码页基础上作了些增补后,作为自己的代码页,并冠以ANSI的字样。我们在“区域和语言选项”高级页面的代码页转换表中看到的包含ANSI字样的代码页都是微软自己定义的代码页。例如:
874 (ANSI/OEM - 泰文)
932 (ANSI/OEM - 日文 Shift-JIS)
936 (ANSI/OEM - 简体中文 GBK)
949 (ANSI/OEM - 韩文)
950 (ANSI/OEM - 繁体中文 Big5)
1250 (ANSI - 中欧)
1251 (ANSI - 西里尔文)
1252 (ANSI - 拉丁文 I)
1253 (ANSI - 希腊文)
1254 (ANSI - 土耳其文)
1255 (ANSI - 希伯来文)
1256 (ANSI - 阿拉伯文)
1257 (ANSI - 波罗的海文)
1258 (ANSI/OEM - 越南)
我们不能直接设置ANSI代码页,只能通过选择系统Locale,间接改变当前的ANSI代码页。微软定义的Locale只使用自己定义的代码页。所以,我们虽然可以通过“区域和语言选项”中的代码页转换表安装很多代码页,但只能将微软的代码页作为系统默认代码页。

2.3 代码页转换表
在Windows 2000以后,Windows统一采用UTF-16作为内部字符编码。现在,安装一个代码页就是安装一张代码页转换表。通过代码页转换表,Windows既可以将代码页的编码转换到UTF-16,也可以将UTF-16转换到代码页的编码。代码页转换表的具体实现可以是一个以nls为后缀的数据文件,也可以是一个提供转换函数的动态链接库。有的代码页是不需要安装的。例如:Windows将UTF-7和UTF-8分别作为代码页65000和代码页65001。UTF-7、UTF-8和UTF-16都是基于Unicode的编码方案。它们之间可以通过简单的算法直接转换,不需要安装代码页转换表。
在安装过一个代码页后,Windows就知道怎样将该代码页的文本转换到Unicode文本,也知道怎样将Unicode文本转换成该代码页的文本。
其实,如果全世界人民在计算机刚发明时就统一采用Unicode作为字符编码,那么代码页就没有存在的必要了。可惜在Unicode被发明前,世界各国人民都发明并使用了各种字符编码方案。所以,Windows必须通过代码页支持已经被广泛使用的字符编码。从这种意义看,代码页主要是为了兼容现有的数据、程序和习惯而存在的。

2.4 SBCS、DBCS和MBCS
SBCS、DBCS和MBCS分别是单字节字符集、双字节字符集和多字节字符集的缩写。SBCS、DBCS和MBCS的最大编码长度分别是1字节、两字节和大于两字节(例如4或5字节)。例如:代码页1252 (ANSI-拉丁文 I)是单字节字符集;代码页936 (ANSI/OEM-简体中文 GBK)是双字节字符集;代码页54936 (GB18030 简体中文)是多字节字符集。
单字节字符集中的字符都用一个字节表示。显然,SBCS最多只能容纳256个字符。
双字节字符集的字符用一个或两个字节表示。那么我们从文本数据中读到一个字节时,怎么判断它是单字节字符,还是双字节字符的首字符?答案是通过字节所处范围来判断。例如:在GBK编码中,单字节字符的范围是0x00-0x80,双字节字符首字节的范围是0x81到0xFE。我们顺序读取字节数据,如果读到的字节在0x81到0xFE内,那么这个字节就是双字节字符的首字节。GBK定义双字节字符的尾字节范围是0x40到0x7E和0x80到0xFE。
GB18030是多字节字符集,它的字符可以用一个、两个或四个字节表示。这时我们又如何判断一个字节是属于单字节字符,双字节字符,还是四字节字符?GB18030与GBK是兼容的,它利用了GBK双字节字符尾字节的未使用码位。GB18030的四字节字符的第一字节的范围也是0x81到0xFE,第二字节的范围是0x30-0x39。通过第二字节所处范围就可以区分双字节字符和四字节字符。GB18030定义四字节字符的第三字节范围是0x81到0xFE,第四字节范围是0x30-0x39

posted @ 2010-02-11 20:57  猪悟能  阅读(1278)  评论(0编辑  收藏  举报