2006年12月25日星期一

Why UTF-8 Sucks

Linux应该用哪一种locale,这还用得着问么,当然是UTF-8。如果在充满愤青的开源论坛上对此提出异议,那你就等着被拍吧。不过我还是有些不同的意见,而且标题为“Why XXX Sucks”的文章看多了,感觉这个句式挺爽,所以今天试着说说,为什么UTF-8也sucks。

首先,使用UTF-8保存文本,会使字节数膨胀。具体增加值根据文本类型会有所不同,对于中文用户而言,UTF-8文件尺寸约为GBK内码的1.5倍。在存储成本越来越低的今天,这的确有点鸡蛋里边挑骨头的味道,所以放在第一个说。

其次,排序方法不符合用户习惯。虽然我没有找到可靠的资料说明Unicode采用了怎样的编码顺序,但翻阅Unicode的码表可以看出,应该是主要采用了笔画序。如果你也像我一样有很多mp3文件,以演唱者为目录名分类存放,你就知道那有多痛苦了。类似的问题其实很容易遇到,例如通讯录中的联系人名单等。

第三,存在不定宽度字符。有一些字符,比如欧元符号、摄氏度符号等,在各种编码中都有定义。传统上中日韩地区将这些字符表示为全宽字符,而其他地区则将这些字符表示为半宽字符。Unicode将这类字符称为Ambiguous,并有文档说明如何处理这些字符。

Ambiguous字符在拉丁语系用户眼里,跟半宽字符是一样的东西,而且还有些“特别的好处”,于是有意将一些文本中半宽字符转用Ambiguous字符表示。而这样的文本在CJK用户看来,就是一塌糊涂。Wordpress不经修改会出现标点符号错误,就是这个原因造成的。

上文提及的三个问题,除了第一个外,其实都有解决的办法。Linux的locale除了指定内码外,还包括语言相关的很多内容,如日期、时间、数字格式等,其中LC_COLLATE就与文字排序有关。不过打开/usr/share/i18n/locales/zh_CN(系统不同位置也可能不同)看看,中文并没有特别制订自己的排序方法,而是直接照搬了ISO14651,跟Unicode内码排序差不多。

至于第三个问题,纯属非CJK地区开发者只图自己方便搞出来的。用Ambiguous字符替换原始字符,不但看起来一样,而且还避免了诸如SQL注入、嵌入非法脚本等问题,简单方便。类似问题也存在于VIM中,VIM有一个参数ambiwidth,默认值为singe。如果将encoding设置为utf-8,并且不修改ambiwidth的设置,对中文引号等字符的描绘就会出问题。

Unicode是为了解决国际化信息交换和处理而出现的,其立志成为所有编码的超集,所以不可能照顾到所有国家和地区的用户习惯。

例如编码顺序的问题,1980年制定的GB2312将汉字分为常用汉字和次级汉字,常用汉字3755个,按照拼音辅以笔形顺序排列,次级汉字3008个,按笔画部首排序。读音依据的是普通话审音委员会发布的文件,而字形则有文化部和文字改革委员会负责。

而Unicode就不可能采用这样的排序方法了,同一个字中文和日文读音不同,甚至大陆和台湾的读音也不同。于是只好用笔画偏旁序,一种机械而折中的方案。

即使采用这种方法,编码制定过程中也大有可吵之处。经过不同国家和地区的使用及演变,一个字的字形可能产生一些细微的变化。是不一样就收,还是有所取舍?取舍时以大陆的中文为准,还是以台湾的中文为准?是听中文的,还是听日文的?这不仅是文化的冲突,还可能牵涉政治问题。

由此可以得出结论,Unicode虽然是一个好东西,但仅有Unicode显然是不够的。一些语言相关的细节问题,商业软件有厂家负责(如MS-SQL就有完备的语言和排序规则),其他的就只能靠政府和我们自己了。只要国内开源社区真的能有所发展,如Wordpress标点符号等类似问题自然可以得到解决。

最后回到开篇那个命题,现下Linux应该使用哪一个locale?我个人的意见是zh_CN.gbk。GBK貌似过时,但其实该标准包含的汉字几乎等同于ISO10646的BMP(Basic Multilingual Plane),日常使用应该足够。而拥有良好国际化支持的程序,例如GVIM、Firefox,并不会因为locale而失去了阅读和处理其他编码的能力。除此以外,Opera、WINE等国际化支持不好的程序,使用zh_CN.gbk也能避免的掉很多莫名其妙的问题。

没有评论 :