DBCS(Double-Byte Character Set, 双位元组字元集)


迄今为止,我们已经看到了256个字元的字元集。但中国、日本和韩国的象形文字符号有大约21,000个。如何容纳这些语言而仍保持和ASCII的某种相容性呢?

解决方案(如果这个说法正确的话)是双位元组字元集(DBCS:double-byte character set)。DBCS从256代码开始,就像ASCII一样。与任何行为良好的内码表一样,最初的128个代码是ASCII。然而,较高的128个代码中的某些总是跟随著第二个位元组。这两个位元组一起(称作首位元组和跟随位元组)定义一个字元,通常是一个复杂的象形文字。

虽然中文、日文和韩文共用一些相同的象形文字,但显然这三种语言是不同的,而且经常是同一个象形文字在三种不同的语言中代表三件不同的事。Windows支援四个不同的双位元组字元集:内码表932(日文)、936(简体中文)、949(韩语)和950(繁体汉字)。只有为这些国家(地区)生产的Windows版本才支援DBCS。

双字元集问题并不是说字元由两个位元组代表。问题在于一些字元(特别是ASCII字元)由1个位元组表示。这会引起附加的程式设计问题。例如,字串中的字元数不能由字串的位元组数决定。必须剖析字串来决定其长度,而且必须检查每个位元组以确定它是否为双位元组字元的首位元组。如果有一个指向DBCS字串中间的指标,那么该字串前一个字元的位址是什么呢?惯用的解决方案是从开始的指标分析该字串。

DBCS故名思义就是用两个byte表示一个字符,是对各种采用两个byte表示一个字符(好像哪里重复了)的内码方案的一个统称。首先要明确的是先有各种双字节编码方案后有DBCS这个(概括性的)名字,DBCS并没有统一的规范,不存在通行的标准。只是早年使用DBCS的各国为了达到类似的目的,最后搞出来的方案大都类似而已。

前提:
  • 早年的ASCII只定义了128个字符(可打印的96个),剩下最高位为1的128个码位算是空出来的
  • IBM搞PC机的时候定义了codepage 437,把高128个码位也用上了,放了各种制表符还有笑脸箭头黑桃红桃梅花方块啥的
  • 就算不管cp437,一个byte里剩下的码位最多也只能表示128个字符,中日韩不够用
基于以上的前提,很自然而然会想到的一种办法就是用两个byte来表示一个字符。ASCII不是空出来了高128个码位吗?第一个byte在这高128里取值,再和第二个byte结合就可以表示最多128x256=32768个字符了。程序在处理字符串的时候,遇到有byte<128的就认为是ASCII,遇到>=128的就把下一个byte也读进来,换算成一个字符。

所以双字节字符虽然保持了和ASCII的兼容性,但天生就和CP437冲突。在具体的编码方案上,各国因地制宜因陋就简因为爱所以爱的制定了不同的方案:
  • 我国的GB2312:
    GB2312诞生于1980年代初,是一个非常克制的码表,高低两个byte都只使用了0xA0到0xFD这一段共94个码位,最大可表示94x94=8836个字符,但其中有若干空位,实际只定义了6763个汉字各种全角字母标点符号等等。早年DOS下的外挂汉字操作系统大多有造字程序,用户可自行指定使用GB2312中未用的码位(当然换台电脑就不行啦)。

    所以对GB2312而言,0x80到0xBF以及0xFE-0xFF的码位是空出来的,相信这也是为了尽最大可能减小和CP437的冲突。主要是CP437里的制表符被覆盖了。

    GB2312只包含最常用的不到七千个汉字,我打赌在看这个回答的人里一定有自己的名字不在GB2312里,高考报名遇到过麻烦的。为了表示更多汉字,GB2312后来扩展了码位变成GBK,占用的码位和下面两个大致类似。

  • 繁体BIG5:
    BIG5的高byte(这里说的高都是以big endian而言)范围为0x81到0xF9,低byte为0x40到0x7E和0xA1到0xFE。注意,GB2312要表示的汉字比较少,两个byte都放到了高128段,这对BIG5远远不够,因而低byte不得不也使用ASCII的低128段。不过程序处理起来也和GB2312没什么区别,反正是以高byte为标志。

  • 日文Shift-JIS:
    SJIS本身不仅仅是DBCS方案,也包括对单字节ASCII表的重定义,但这里只说双字节。和BIG5类似,SJIS的高byte是0x80到0xFF,低byte也同时占用了0x40到0x7E和0x80到0xFC。

要特别提一下0x7F,在ASCII里这是表示删除的控制字符,在早期的电传里会用到,所以BIG5和SJIS都专程避开了它。

从上面可以看出,各国的DBCS方案虽然原理类似,但实际占用的码位都有区别,并不是单纯靠检查byte的最高位是不是为1(即大于127)来判断的。例如GB2312,小于0xA0的都不算。

在UTF8还没有流行起来的年代,和各种DBCS打交道很苦逼的。DOS下面很多软件在字符界面下画窗口的时候用到了CP437里的制表符,比如QuickBASIC或TurboC,一旦外挂中文系统开起来就自然而然变成了奇怪的中文。所以那时候的外挂中文系统们又发展出来一种奇怪的能力,就是智能识别当前的内容应该显示成英文制表符还是中文,并且识别准确率还作为一项卖点出现在广告里……

那就更不要说GB2312, BIG5, SJIS混杂的情况了。10多年前我记得大连理工有个年轻老师还开发了一个叫autoconvert的开源软件能智能识别一段文本到底是使用了哪种编码。


作者:rlei
链接:http://www.zhihu.com/question/26502361/answer/33008465
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值