对字符编码的学习理解

来源:互联网 发布:java多进程同步 编辑:程序博客网 时间:2024/04/30 00:57
我以前从事计算机底层工作,比较少涉及到各种中文英文字符集及其转换。最近学习Java+Mysql时碰到了这个字符设置问题,思考一阵后我从比较熟悉的底层的角度来理解这个问题。

字符指人类或智能模块能理解的语句或数据的组成元素,例如字符串“Hello world”里面的各个字符。计算机底层以及网络传输层并不懂字符,只懂得01010101这样的二进制编码,故字符必须转换为二进制编码后才能通过计算机底层及网络进行交流传送。这个从字符到二进制编码的对应关系是一个键值对集合,也即所谓的字符集。由于历史或其他的原因,存在各种不同的从字符到编码的键值对应关系,也即不同字符集。

在不同的计算机底层或传送模块中可能会采用不同的字符集来对字符进行编码,因而同一个字符串可能在系统中的不同位置表现为不同的二进制序列。这并不妨碍信息的传播,只要每个地方的二进制序列能转换出“Hello world”,则说明信息“Hello world”被正确传播了。我认为这是理解字符集及其在系统各地进行编码转换的基础。

先测试一下字符串“aabbcc你AABBCC”的可能编码。首先打开windows记事本,键入字符串“aabbcc你AABBCC”,然后分别保存为ansi、unicode和utf-8格式的文件,再用UltraEdit打开文件并选择16进制模式查看:

    用ansi字符集编码后的文件内容:
        00000000h: 61 61 62 62 63 63 C4 E3 41 41 42 42 43 43       ; aabbcc你AABBCC
    用unicode字符集编码后的文件内容:
        00000000h: FF FE 61 00 61 00 62 00 62 00 63 00 63 00 60 4F ; .a.b.b.c.c.`O
        00000010h: 41 00 41 00 42 00 42 00 43 00 43 00             ; A.A.B.B.C.C.
    用utf-8字符集编码后的文件内容:
        00000000h: EF BB BF 61 61 62 62 63 63 E4 BD A0 41 41 42 42 ; 锘縜abbcc浣燗ABB
        00000010h: 43 43                                           ; CC

可见:
    ansi编码最简洁,英文字符就是ASCII编码,中文“你”被编码为“C4 E3”。
    unicode编码有前缀“FF FE”,每个英文是ASCII编码但扩展了一个“00”字节,中文“你”编码为“60 4F”。
    utf-8编码有前缀“EF BB BF”,每个英文是ASCII编码,中文“你”编码为“E4 BD A0”,竟然是3字节。

假定模块A采用ansi字符集做编码,模块B采用utf-8做字符集编码,要在A和B之间传递字符串“aabbcc你AABBCC”,注意每个模块都要按自己的字符集编码方式来保存信息“aabbcc你AABBCC”,于是可能有两种方案:
1、模块A将二进制序列“61 61 62 62 63 63 C4 E3 41 41 42 42 43 43”发送给B模块,B模块收到后将这个序列转换成“EF BB BF 61 61 62 62 63 63 E4 BD A0 41 41 42 42 43 43”并保存。那么模块B需要知道模块A采用的是ansi字符集,否则B无法将二进制码正确地解码为字符串,会出现乱码,后续更无法做本地的utf-8编码了。
2、模块A将二进制序列“61 61 62 62 63 63 C4 E3 41 41 42 42 43 43”转换成模块B应有的“EF BB BF 61 61 62 62 63 63 E4 BD A0 41 41 42 42 43 43”序列,再发送给模块B。那么模块A需要知道模块B采用utf-8字符集才知道怎样构造传递给B的二进制码流。

在Java+Mysql系统里面采用的应该是方案1,也许所有系统都是这样。假定在浏览器上显示的网页的编码是utf-8,则说明网页表单的字符串数据将按utf-8来编码出二进制流,这个二进制流被提交到tomcat服务器。但tomcat服务器的缺省编码可能是ISO-8859-1,也即会按这个编码来解读数据,于是发生乱码。解决方案是用request.setCharacterEncoding("utf-8")这类命令通知服务器按utf-8来解读数据,于是客户端和服务器的编码方式就一致了,就不会乱码了。总之,要让传输两端都用同一个字符集做编码即可。

我仿佛记得资料上说,从客户端提及的数据中没有字符集的说明,于是服务器只能猜测或固定设置字符集?这就不是很完美和灵活了,这似乎是个设计不周到的悲剧。