2.3.2 文字数据在计算机中的表示
1.西文字符的二进制编码
现代计算机不仅可以用来进行数值运算,也可以用来进行文字处理。同样,要完成文字处理任务,就必须解决各种文字在计算机中表示的问题。例如,如果希望计算机处理英文,就需要解决在计算机中表示“A”, “B”, “C”等字母的问题;此外,也还要解决在计算机中表示句号、逗号等标点符号的问题。
文字、符号在计算机中表示常常采用编码的方式,即为每个可能用到的字符分配一个二进制编码。例如,用编码65来表示字母A,这样A在计算机中就被存储为65的二进制数形式。为了可以用同样的方式处理文字信息,所有计算机必须采用同样的编码方案;否则,不同的计算机中的文字信息在交换时就会发生混乱。这可以通过文字符号编码的标准化来实现。西文字符最常用的编码标准是美国标准信息交换代码(America Standard Code for Information Inter-change, ASCII)。ASCII编码标准规定了大小写英文字母、数字,标点符号以及一些常用符号的二进制编码。标准的ASCII码是7位二进制编码,所以其中包含了128个字符的编码。在计算机中进行表示时,每个字符可以用一个字节表示。由于标准ASCII码是7位二进制编码,所以字节的最高位为0。完整的标准ASCII码表如表2-4所示。
表2-4 标准ASCII码表
在表2-4中,某字符的二进制编码被分成高四位(H)和低四位(L),以字母“A”为例,编码的高四位是0100,低四位是0001,故其ASCII码是01000001。又如,右圆括号“)”的ASCII码是00101000。
从表2-4还可以看出,除A~Z, a~z,0~9以及标点符号、特殊符号之外,ASCII码中还有部分用于编码控制字符,其编码范围为0~31。它们不属于文字编码,而是一些控制码,常用于控制输入、输出设备等。例如,编码00001010(表中标记为“LF”)实际上是用来控制在输出设备上换行的控制码。
需要说明的是,即使针对印欧语言,ASCII码表也没有列出人们所希望处理的所有符号。例如,ASCII码表中没有德语中的变元音“ä”,因此,如果只采用标准的ASCII编码,就无法很好地处理德语文本。为了能对更多的文字、符号进行编码,目前计算机常常采用扩展的ASCII编码。这是8位二进制编码,因而可以表示256个字符。其中,0~127编码和标准ASCII码一样;而在编码范围128~255内,又增加了一些其他的字符,如特殊的德语和法语字母。扩展的ASCII码是国际标准化组织(International Organization for Standardization, ISO)的标准,通常称为ISO 8859,根据语系的不同,又可分成不同的标准,如ISO 8859-1、ISO 8859-2等。
有了ASCII码或ISO 8859码,现代计算机就可以处理大部分西文。例如,字符串“Hello,(空格)World! ”在计算机中就表示为包括所有字符(包括标点和空格)的ASCII编码,即
01001000011001010110110001101100011011110010110000100000
010101110110111101110010011011000110010000100001
2.汉字的二进制编码
同西文字母一样,汉字也必须经过编码才能为计算机所处理。在对西文进行编码时,通常采用ISO 8859等编码标准。ISO 8859中共有256个字符编码。可是汉字的数量成千上万,远远大于256个,如《康熙字典》中收录的汉字就有四万多个。因此用1字节的编码空间进行汉字的编码是不现实的。对于汉字而言,编码需要至少两个字节。若用两个字节进行编码,那么理论上可以有65536(即216)个不同的编码;也就是说,可以对65536个汉字进编码,这完全可以满足对汉语文本进行处理的需要。基于这样的思路,我国大陆先后颁布了多个有关汉字编码的官方标准,包括GB2312, GBK以及GB18030,通行于我国大陆地区和新加坡。与此同时,我国台湾地区也颁布了有关的汉字编码标准,如BIG-5(又称大五码),并在香港、澳门和台湾地区得到广泛的使用。
公布于1981年的“信息交换用汉字编码字符集基本集”(称为GB2312-80)共收录了7445个字符,其中包括汉字6763个,其他符号682个。对于汉字,又分做两级:一级汉字(3755个)为常用字,按照音序排列;二级汉字(3008个)多为生僻字,按照部首序排列。GB2312编码方案把编码空间分成94个区,并在每个区中设94个位,每个位中放置一个汉字或符号(图2-8)。GB2312码规定,在94个区中,01~09区是符号、数字区,包括汉语的标点符号、常用的货币符号、图形符号、数学运算符号、各种形式的数字序号以及日文的假名符号;16~87区是汉字区,包括所有两级共6763个汉字位于这一区段;此外,10~15区和第88~94区是没有定义的空白区,目的是为以后的扩充或用户自行定义编码留下空间。
图2-8 GB2312编码标准中的第16区
收入GB2312编码标准中的每个汉字或符号都有一个唯一的区号和位号与之对应;反过来,每个区号和位号可以唯一地确定一个汉字或符号,例如:符号“〖”位于1区第28位,汉字“啊”位于16区第1位。将汉字的区号、位号这两个数合起来称为汉字的区位码,例如“啊”字的区位码是1601,写成16进制数是1001H。
在通信领域,代码0~31(十六进制数00H~1FH)常被用做控制码,因而区位码不能直接用于通信,因为区位码与这些通信控制码之间存在冲突,即一个位于0~31区间内的编码既可能表示一个控制码,也可能表示一个汉字的区号或位号。为了消除两者在编码空间中的重叠,汉字在通信时,其区号和位号要分别加32(十六进制数20H)。这样形成的汉字代码可以用于通信领域,被称做汉字的国标交换码(简称交换码或国标码)。例如,“啊”字的国标码是4833(十六进制数3021H)。
然而,汉字编码要进入计算机内进行处理,还必须考虑到汉字与西文字母的冲突问题,因为一个文本中既可能有汉字,也可能有西文字母。标准的ASCII码为7位二进制数的编码,其编码范围位于0~127(十六进制数00H~7FH)之间;国标交换码的两个部分的范围均为33~126(十六进制数21H~7 EH),因此国标码和ASCII码也存在冲突,即对于文本中的某个字节,计算机系统无法确定该字节代表的是用ASCII码表示的西文字母,还是用国标交换码表示的汉字两个字节编码中的一个字节。由于标准ASCII码是7位,用一个字节表示时,其最高位总为0;而国标交换码的两个部分的范围均为33~126,每个部分用一个字节表示时最高位也为0,因此只要把汉字国标码的每个字节的最高位置为1,汉字和西文ASCII的编码就可以有效地区别开了。对于文本中的任何一个字节,若其最高位是0,则该字节代表一个西文字符;若其最高位是1,则该字节及其后一个字节代表一个汉字。在国标交换码的基础上,将字节最高位置1形成的汉字编码,一般称为机内码。图2-9以“啊”字为例,说明区位码、国标交换码以及机内码的区别和联系。
图2-9 区位码、国标码和机内码的关系(以“啊”字为例)
需要说明的是,目前计算机系统正是采用机内码来表示汉字的,这一点需要明确,计算机系统并不采用区位码或国标交换码表示汉字。通常所说的GB2312码实际多指的是这种机内码。
GB2312码属于双字节字符集;也就是说,需要用两个字节来表示一个汉字或符号。由于所有汉字和符号被区分成94个区和94个位,故而GB2312码中最多可容纳8836(即942)个汉字。除去数字符号区以及没有定义的空白区外,GB2312码仅包含了6763个汉字。一定程度上,GB2312码已基本满足了我国汉字处理的需要。汉字数量虽多,但常用的却不过三千多个,据有关统计,各类出版物中90%以上的版面由这些常用字组成,GB2312码中收录的6763个汉字可以覆盖各类出版物中99%以上的版面。但是在有些应用场合中,使用GB2312码仍然面临收录汉字过少的问题。例如我国有许多人名、地名用字生僻,GB2312码中可能没有收录,导致这些人名、地名无法有效用计算机处理。又如,在一些特殊的应用领域(如面向辞书、古代汉语的出版领域),涉及较多的生僻用字,GB2312码也远远不能满足需要。
为了更好地满足中文信息处理的需求,需要针对GB2312码进行扩充,从而可对更多的汉字进行编码。1995年,我国大陆地区发布了《汉字编码标准扩展规范》(称为GBK,也称为GB13000)。GBK码是对GB2312码进行的扩展,共收录汉字和符号21886个,其中汉字21003个。GBK仍然是两个字节的编码,细心的读者也许会发现,在GB2312码的机内码中,两个字节的最高位都是1,那么只有14个二进制位用于实际汉字编码,这样的话,理论上只能对16384(即214)个汉字进行编码。在GBK码中,并不要求两个字节的最高位都置1,而仅仅要求第一个字节的最高位为1。这同样可以保证计算机有效区分中文和西文字符。若文本中的一个字节最高位是0,那么该字节代表一个西文字符;若字节的最高位是1,那么无论该字节后一个字节的最高位是否为1,计算机均会把该字节及其后一个字节作为一个汉字来对待。因而,在GBK中,两个字节中有15个二进制位用于汉字编码,从而有效地扩充了汉字的编码空间。
2000年,我国大陆地区又发布了GB18030汉字编码标准,对GBK码再次进行扩展。该标准收录了27484个汉字,同时还收录了藏族、蒙古族、维吾尔族等少数民族的文字。GB18030不再是固定长度的编码,其编码长度可以是一个、二个或四个字节。
GB2312, GBK以及GB18030并非完全不同的汉字编码标准,这些编码方法之间存在着继承关系。套用信息技术领域的行话来讲,这些编码方法是向下兼容的;也就是说,除了新增加的汉字和符号外,同一个汉字或符号在这三种编码方法中的编码总是相同的。例如,“啊”字在计算机系统中的机内编码用十六进制表示是B0A1H;在采用GBK以及GB18030的计算机系统中,其机内编码仍然是B0A1H。这有效保证了在采用GB18030的计算机平台中仍然可以正确处理采用GB2312或GBK规范进行编码的汉语文本。
同GBK类似,由台湾财团法人资讯工业策进会于1984年发布的BIG-5码也属于双字节编码,共收录13868个汉字和符号。BIG-5码目前通行于香港、澳门和台湾地区,与GB2312、GBK以及GB18030等编码间并没有兼容关系,同一个汉字在BIG-5以及GB码中的编码是不同的。采用BIG-5编码的电子文本必须首先转换为GB码,才能在采用GB码的计算机平台中处理和使用。
3.Unicode编码
长期以来,字符编码标准的制订各自为政,不同的语言需要不同的编码标准。为了使计算机能够处理汉语,我国需要制订汉字的编码标准。同样,为了使计算机能够处理韩文、日文,韩国、日本也需要制订相应的字符编码标准。同一种语言甚至还存在多种编码标准。没有任何一种字符编码标准可以覆盖世界上所有语言的文字和符号,这给计算机处理各种文字信息,尤其是多语信息带来了很大障碍。计算机系统常常需要支持多种编码标准。此外,由于各种编码标准的制订并没有考虑其他编码标准,所以各种编码的编码空间常常存在冲突,同一种编码在不同的标准中对应着不同的字符。改变这一局面的唯一办法是制订一种可以覆盖所有语言文字和符号的编码标准。Unicode就是这样一种编码,为每种语言的每个字符设定一个统一且唯一的编码,以满足统一、高效处理世界上各种语言的需要。
Unicode字符集有两种格式:一种采用双字节进行编码,称为UCS-2;另一种采用四字节编码,称为UCS-4。UCS-4规定最高位必须是0,所以实际上是31位的编码,并且根据最高字节(最高位为0的字节)把所有编码空间分成128组;每组根据次高字节分为256个平面;每个平面再根据第3个字节分为256行;每行包含256个单元。第0组的第0个平面被称做基本多语种平面(basic multilingual plane, BMP),其中的字符前两个字节的值总为0。将UCS-4中的BMP去掉前面的两个零字节,就得到了UCS-2。目前的UCS-4规范中还没有任何字符被分配在BMP之外。
在计算机系统中,直接使用UCS-4或UCS-2并不方便,例如,其中有大量的零字节,而零字节在很多计算机程序设计语言中有特殊的含义,因此在计算中多采用UCS的变换码,即UTF编码。常见的UTF规范包括UTF-8和UTF-16,下面简要介绍UTF-8。
UTF-8是变长编码,理论上可以多达6个字节长;不过对于16位BMP字符最多只用到3个字节长。从UCS到UTF-8进行变换,遵循表2-5的原则。
表2-5 UTF-8编码规则
例如,在UCS-2中,汉字“啊”的编码是554AH(二进制数0101010101001010),位于表2-5中第三行的区段内,故“啊”的UTF-8码是111001011001010110001010,即E5958AH。因此在UTF-8中,汉字用第三个字节进行编码。再如,在UCS-2中,西文字母“A”的编码是0041H,因其位于表2-5中第一行的区段内,故“A”的UTF-8码是41H。可见,在UTF-8中,拉丁字母仅用一个字节进行编码。
在UCS-2中,区段00000000H~0000007F中被分配给了标准ASCII,在变换成UTF-8时,这些字符的编码均为一个字节长,和ASCII码是完全相同的,因此UTF-8和ASCII码是向下兼容的。但UTF-8和GB码是不兼容的,属于不同的编码标准,在两者之间进行转换,需要凭借专门的编码转换软件。