找回密码
 骑士注册

QQ登录

微博登录

搜索
❏ 站外平台:

Linux中国开源社区 观点 查看内容

对于Windows,GB18030是不可用的

2013-04-20 17:46    评论: 3 收藏: 1    

疑惑二:54936代码页的真相?

既然CP54936在所有的代码页中显得如此之特殊,这不得不让人产生了一窥其具体技术细节的欲望。我们知道:对于代码页机制来说,不同代码页间的主要区别在于各个位置上的字节取值范围的不同。比如CP936的引导字节范围在0x81-0xFE之间,尾随字节范围在0x40-0x7E或0x80-0xFE之间;CP932的引导字节范围在0x81-0x9F或0xE0-0xFC之间,尾随字节范围在0x40-0xFC(0x7F除外)之间。显然CP936和CP932有 很大的不同,这种不同成了系统在当前代码页下,区分哪些是有效编码(字符)和无效编码(字符)的依据。

言归正传,虽然Windows需要重启才能改变当前 代码页,但要查看某个代码页的信息却不用那么麻烦。在任意一个代码页下,随时都可以用API函数GetCPInfo读出包括当前代码页在内的所有系统支持 的代码页的属性信息。

我们先用最熟悉的CP936试看看,测试结果GetCPInfo返回的信息如下:MaxCharSize=2;LeadByte={81,FE,00,00,00,00,00,00,00,00,00,00}。这个结果的意思是说:CP936的字符最大编码长度是两个字节,它的引导字节有一个取值范围:0x81-0xFE。显然GetCPInfo(936)返回的信息跟我们所了解的GBK编码标准的技术框架是符合的。

接下来看看我们所关心的CP54936的情况,测试结果GetCPInfo返回的信息如下:MaxCharSize=4;LeadByte={00,00,00,00,00,00,00,00,00,00,00,00}。按照Windows代码页机制的说法,这个结果意味着CP54936没有引导字节取值范围的定义,而这种情况通常只有单字节ANSI编码才会出现。

难怪Windows没有提供把54936设为系统当前代码页的选项了,因为即使把CP54936设为当前代码页,那些ANSI字处理程序(也就是非Unicode程序)也是无法显示和编辑GB18030编码的文本的。

这一点可以很容易地从Windows的代码页技术原理上分析得到:CP54936没有定义引导字节的取值范围,但它本身又是一种ANSI编码的代码页,所以当系统运行在这个代码页下的时候,实际上等于是运行在单字节ANSI编码的代码页下面。

这样一来,当我们试图在ANSI程序里面显示一个四字节编码的GB18030字符的时候,系统会毫不客气地把它识别为无效编码(字符),实际显示出来的就是一堆的问号了。这是因为单字节ANSI编码的每个字节取值都不会超过0x7F的,而GB18030的四字节编码的第一、三个字节的取值都在0x81以上,根据Windows代码页的技术规则,当然会被判定为无效编码(字符)了。

注:Windows的代码页技术原理并不难理解。系统里面对应不同的代码页存储了不同的代码页属性――包括这个代码页所代表的编码标准的最大字符存储长 度(单位:字节);引导字节取值范围;尾随字节取值范围(这个是隐藏的,用GetCPInfo函数是得不到它的,但它确实存在,看来微软还是习惯性地留了 一手)。

系统存储这些代码页属性最主要的目的就是用来判断某个给定的字符串里面是否包含有不符合当前代码页编码框架的字符(编码),当然这种判定是对于那 些准备要送去给程序中需要显示在用户界面上的字符串(文本)而言的。对于发生在计算机内部(内存)里面的文本处理过程(比如文本文件的内码转换),是不需 要进行这种判断的。

这也就是为什么说文本文件的转码不需要特定系统的支持的原因。系统判断有效编码(字符)和无效编码(字符)的过程是这样的:顺序读取字 符串中每个字节值,如果出现一个取值不在当前代码页属性许可的取值范围(比如在单字节代码页中出现大于0x7F的字节)内的字节的话,那么这个字节所属的字符就是无效字符,在软件界面上就会被显示为问号。

对于双字节编码的代码页(Windows支持的代码页都是单字节或双字节代码页,只有CP54936是四字节这个例外),如果读出的某个字节值小于等于0x7F,就说明它是一个单字节字符;如果读出的字节值大于0x7F, 就把它当成引导字节处理,看看这个字节值是否在当前代码页指定的引导字节取值范围内,以及它的下一个字节值是否在当前代码页指定的尾随字节取值范围内。如 果这两个条件都成立,说明当前读到的这个字节和它的下一个字节组成了一个有效的双字节字符,否则当前字节值判为无效编码,显示为问号。

上述这个判定过程是真实存在的,完整的编码有效性判定工作需要引导字节取值范围和尾随字节取值范围两个基本信息的支持。只是不知道微软出于什么原因,只 开放了引导字节取值范围,但从Windows在文本处理上的一些行为中,是可以发现尾随字节取值范围信息是肯定存在的。

比如,在简体中文系统下(CP936)写一个ANSI的小程序:这个程序的界面包括一个Edit控件和一个Button控件(两个控件的字体属性已经设置成了"宋体-18030"),编写Button控件的鼠标单击过程实现把一个编码字节值序列为的ANSI字符串赋值给那个Edit控件让它显示"䢎"(0x82348434是CJK ExtA汉字"䢎"的GB18030编码)这个字的功能。做这个实验程序的目的是要测试在CP936代码页下,ANSI程序是否能支持GB18030编码字符的显示和编辑。该程序的运行结果是,按下Button按钮之后,Edit编辑框里面并没有如希望的那样显示"䢎",而是??。

显然Windows认为在当前代码页(CP936)下面,0x82348434是两个非法字符。因为这个编码字节序列由四个字节组成,当系统读出第一个字节0x82的时候,因为这个字节值大于0x7F,所以需要判断它和下一个字节0x34能否组成一个双字节字符,而由于0x34不在GBK尾随字节取值范围之内,所以第一和第二字节被判定为无效编码;而第三字节的0x84和第四字节的0x34也是一样的。所以这四个字节组成的编码序列被判定为两个无效字符,在软件界面(Edit控件)上被显示成了两个问号。

系统的这一处理结果反映了尾随字节取值范围信息的真实存在,否则很难想象它怎么会把0x8234判断为无效字符。因为根据双字节ANSI编码框架的一般规则:组成双字节字符的前后两个字节中,第一个字节必须大于0x7F以便文本处理程序把这个字节和单字节字符编码区分开来。而对第二个字节的取值范围并不作特别的规定,可以是任意取值范围(包括小于等于0x7F的ASCII编码值范围)。如果系统中没有存储GBK尾随字节取值范围定义的话,由于第一个字节0x82已经符合GBK引导字节取值范围的要求了,第二个字节不管取什么值都应该判定这两个字节组成的字符是有效的双字节字符。而事实是Windows准确地判断出了0x8234不符合GBK的双字节编码框架,这只能说明它是清楚地知道GBK的尾随字节取值范围定义的。

查看其它分页:

最新评论

我也要发表评论

微博评论 2013-04-20 18:34 1 回复
根据Unicode来指定国标,那样多简便啊

来自 MAGI一只鱼向南 的新浪微博
tempwall 2013-04-21 20:15 1 回复

且不说文章时效性问题,这篇文章标题党的意味很重。Windows对18030支持如何,稍微了解一下就能知道。也不清楚这种文章究竟是如何流传的,竟然还可以加精?

"可是让人难以理解的是,在安装了18030支持包以后,"代码页转换表"里面已经显示"54936(GB18030 简体中文)"代码页是可用使用的了。但在"非Unicode程序语言版本"列表里面,却没有相应地提供一个类似"中文(中国GB18030)"这样的选项,也就是说:Windows根本就没有提供给我们把代表GB18030编码标准的54936代码页设为系统当前代码页的选择。"

这种信口开河都能堂而皇之地跑出来,才是真正的难以理解和笑话……

博派大黄蜂 2013-04-21 22:31 1 回复
我只过惠普的BIOS是繁体中文的

收藏

返回顶部

分享到微信

打开微信,点击顶部的“╋”,
使用“扫一扫”将网页分享至微信。