小时候刚开始学程序设计的时候就为了中文编码而头痛,尤其是做JSP的时候。不是页面显示不对,就是参数获取上有问题。记得经常和Vincent两个人很快把程序架构写好后,要为了字符编码问题忙上好久。
在第一次飞法国的飞机上就想过,终于可以不用为了编码而困扰了。工作后,公司的项目都是英、法、德三种语言,没有超越Latin1字符集。默认的工作环境也是ISO-8859-1编码集。一年多以来,倒也是相安无事。
最近,开始了一个新项目。不算很大的工作量,也没有什么陌生的技术,一开始进展很是顺利。但是在实际测试时发现了问题,就是表单数据的字符编码。这个项目有两个版本,罗马尼亚语和土耳其语。这两种语言都超越了西欧Latin1字符集,却又分属于ISO-8859-2和ISO-8859-9两个不同的编码集。
其实完全可以全部用UTF-8编码了事。但是公司的Tomcat和MySQL全局环境都显式配置为ISO-8859-1,而且在庞大的底层程序中有好几处都硬编码成Latin1。更改全局配置是不可能的,也不想冒极大的风险来修改底层类。
最后完全迷失于编码转换中……很神奇的是没有乱码出现。Latin1以外的字符被转换成HTML格式编码了。所以就用了很恶心的方法,把读入的表单数据从8859-1读入转换成UTF-8(HTML <-> UTF是很容易的)后再转成8859-2/9显示(由于客户方终端不支持UTF-8方案,不能直接用输出Unicode)。尽管8859-1编码集不支持Latin1字符集以外的字符,但是这层转换的内部处理还是通过Unicode,不存在信息丢失问题。说白了就是UTF-8 -> ISO。
不过数据库中的数据却始终无法正常存储。数据永远以乱码读出,而且无法转换。奇怪的是,如果把控制台编码换成8859-2/9的话,可以在数据库中看到正确的数据。但是运行
SELECT HEX(column) FROM table
得到的结果却是错误的。获得的十六进制编码是信息经过
8859-1编码后的Unicode值。这个问题涉及到系统底层类,数据库配置等多个方面。Rene甚至不知道在数据库中贮存的到底是什么。
最后的理解是这样的,底层接口类把数据转换成8859-1编码存入数据库,同样也以8859-1读出。SQL请求以字节流返回,这也说明了在控制台下可以用8859-2/9编码看到正确结果。但是中间结果由于全局配置的关系,被编码成8859-1,所以显示的Unicode值不对。在程序中,由于数据取出后被强制转换成8859-1编码,所以造成了信息丢失。就再也找不回Latin1以外的字符了。
最终的解决方案,让Rene恶心到可以从Montparnasse上跳下来。由于数据在存入数据库前是正确的,其实在存入时也是正确的。所以打算在存入前,把信息转成十六进制编码。理论上应该是可行的,就是会很难看,非常非常难看。