炒冷饭,谈中文处理

来源:互联网 发布:网络皮肤医生在线咨询 编辑:程序博客网 时间:2024/06/11 17:13

国际化支持,多语言,本地化,这些概念的背后都是"字符串"的内容和相关操作是否是多字节安全的.

字符串编码存在的本质是计算机只能存储和处理"数字",所以人类沟通中使用的字符串必须转化为"数字串"的方式才能被计算机处理或者在网络上传输.将字符串中的每个字符转换到特定数字组合的规则就是字符编码.

ascii编码是最常见的用来编码英文字符的单字节编码方式,对于字符串"hello",使用ascii编码后的"数字串"用十进制表示就是[104,101,108,108,111].

对于中文,日文,韩文等亚洲文字,一个字节能表示的最大数值已经无法容纳映射后的用来代表某个字符的数值,所以多字节编码方式就成了必然,中文的GB2312,GBK,GB18030编码标准的制定就是为了完成这个任务.然而,使用多字节存储一个数值的时候,又会遇到一个问题,就是字节存储的顺序(BIG ENDIAN/BE和LITTLE ENDIAN/LE的由来,这点上,不仅仅在存储字符编码时会遇到,任何用到多字节存储的时候都会碰到这个问题).对于GB2312,GBK,GB18030,不仅仅一个中文字符映射到的数值是确定的,并且这个数值字节存储的顺序也是确定的.

到这里,可以看出,对于中文的处理,有两个步骤: A.将一个汉字映射到一个数值; B.将这个数值按照某种约定的字节存储顺序存储,操作,传输.

这时,再引入国际标准的字符编码UNICODE.对于步骤A,UNICODE编码已经包括所有人类使用中的字符;对于步骤B,UNICODE标准也定义了多种方法,UTF-8,UTF-16,UCS-2是常见的几种.

编码的概念暂时到这里,剩下不得不提的就是应用程序在处理多字节字符时的编码问题.同样,两个司空见惯的操作: 1. 用文本编辑器(纯文本)输入中文保存到文本文件中; 2. 在终端(windows的cmd窗口, *nix上的各种terminal)将文本文件的内容dump出来;

对于中文windows操作系统(内码使用UNICODE)上,中文字符可以很顺利的在编辑器和终端中显示出来.理所当然的背后就是操作系统已经为文本编辑器和终端提供了足够的字符编码信息:文本文件将使用GBK编码方式存储中文字符;终端可以假设接收到的字节流是GBK编码的字符串. 这里的GBK编码方式(windows操作系统内部的codepage序号为936,所以又经常可以看到cp936的中文编码名称)就是操作系统默认字符编码.

然而网络服务程序(例如,HTTP服务器)无法为客户端OS的默认字符编码做任何假设,所以最好的方法就是在将文本内容的字节流传输给客户端之前,先通知客户端字节流将采用的字符编码方式.这就是HTTP报文header里,"Content-Type"字段中"charset"的作用(Content-Type: text/html;charset=gb2312).出现乱码的页面,几乎可以确定要么是缺失该信息,要么就是该信息错误.

最后,几行代码,描述一下Java,Python,Ruby的字符编码转换API,方便日后查阅. *注意,源代码文件都使用utf-8方式存储,操作系统默认编码为GBK.

Java:

String s = "你好";byte[] b1 = s.getBytes("utf-8");byte[] b2 = s.getBytes("GBK");s = new String(b1, "utf-8");//OK! 等效new String(b2, "GBK")System.out.write(b1);//向终端直接写字节流.乱码!System.out.write(b2);//OK! 等效System.out.print(s)

Python:

# coding=utf8s = u"你好"sys.stdout.write(s.encode("GBK"))//OK! 等效print ssys.stdout.write(s.encode("utf-8"))//乱码!

Ruby:

require 'iconv's = "你好"puts s//乱码!puts Iconv.conv("GBK", "UTF-8", s)//OK!