一种对汉字更环保的 Unicode 编码方案

标准|cnBeta.COM| 2008-12-25 01:11:44

Windows 早期默认支持的中文编码方案是 GBK,它是对早期 GB2312 的一个扩展。后来国家又发布了 GB18030 标准,扩展了 GBK,增加了一些 Unicode 里才有的汉字,这样就可以做到和 Unicode 字符集做完全的映射了。而后来 Unicode 逐渐成为标准,几乎所谓的系统处理多国语言时,都把 Unicode 做为默认设置了。Unicode 有两套编码集,UCS-2 和 UCS-4,后者是对前者的补充,虽说字面说写的 4,但实际上只用到了 3 个字节不到。

Windows 的内部其实是用的 UCS-2 标准,并用 UTF-16 来实现。而非 Windows 系统大多采用了 UTF-8。UTF-8 在很多情况下更有优势,首先它不需要考虑大头小头的问题,其次,数据损坏的时候,不会有半个汉字的问题。并且 UTF-8 可以完整的表达 UCS-4 而不需要有额外的付出。

前几年,在 Windows 程序员过度期,经过一些痛苦的实践,我终于意识到,VC 提倡的所谓为软件维护 UNICODE 和 非 UNICODE 两个版本是件巨傻 X 的事情。之后,我们的程序再也不为内码分版本了,一律采用 UTF-8。

不过,UTF-8 的设计明显是用英文为主的西方人搞出来的东西。对于中文一点都不环保。所有汉字和中文标点都需要 3 个字节才能表达。而少量欧洲字母可以用 2 字节表达,英文的 ASCII 符号则可以只用单字节。

我不指责这个设计,因为兼容 ASCII 是 UTF-8 的最大优势。其它,则是 KISS 原则下的产物。

不过,若是内部使用的话,如果你介意这 1/3 的储存空间的浪费的话,是不是有改进的余地呢?下面我们来讨论这个问题。

观 察 Unicode 的码表我们可以发现,实际大部分汉字是从 U+4E00 开始编码的,到 U+9FFF 结束。U+2000 到 U+3FFF 则有一些汉字标点符号等。稍加设计,我们可以定义出一种编码方案,对 UCS-2 或 UCS-4 做编码,让汉字可以用双字节表达,并保持对 ASCII 的兼容(U+0000 到 U+007F)段依然使用单字节。

作为牺牲,那些欧洲字母和韩文,就委屈到 3 字节甚至更长的编码了。

简述一下对 UCS-2 的编码方案(UCS-4 只需要做点小扩展)。

使用 大头方案(Big-endian)

ASCII 部分 U+0000 到 U+007F 保留,用单字节 0x00 ~ 0x7f 表达。

对于 U+2000 到 U+9FFF,除掉其中的 U+2F00 到 U+2FFF 部分(目前这个部分为空),做一个简单变换:即加上 0x6000,把编码转换到 0x8000 到 0xffff 部分。做双字节编码。由于 U+2F00 到 U+2FFFF 被除外(如果是 UCS-4 可以去除 U+2E00 到 U+2FFF),所以 0x9f 将成为一个 magic number。

对于其它部分:U+0080 到 U+1FFF,U+2F00 到 U+2FFF,U+A000 到 U+FFFF,一律编码到第 2 3 字节。并将第一字节直接设为 0x9F。

这样,解码成 UCS-2 的算法非常简单(甚至不比 UTF-8 解码更复杂)。缺点是,缺乏 UTF-8 的容错性,有半个汉字的隐患。

这样的编码什么时候会有用?

网络传输时,对字符串做这样的编码(写一个 UTF-8 到这个特定编码方案的互转程序可以在 10 行 C 代码内完成,并非常高效),可以有效减少传输的数据。

如果需要做大规模的数据储存,比如搜索引擎抓取的网页时,可以节省不少储存空间。

至于源代码,和配置文件中,还是推荐使用 UTF-8,毕竟编辑器的支持更重要。

作者:云风