字符、字节和编码
?
3.4 从数据库读取字符串?
通过数据库客户端(比如 ODBC 或 JDBC)从数据库服务器中读取字符串时,客户端需要从服务器获知所使用的 ANSI 编码。当数据库服务器发送字节流给客户端时,客户端负责将字节流按照正确的编码转化成 UNICODE 字符串。?
如果从数据库读取字符串时得到乱码,而数据库中存放的数据又是正确的,那么往往还是因为前面提到的“误解一”造成的。解决的办法还是通过 string = new String( string.getBytes("iso-8859-1"), "GB2312") 的方法,重新得到原始的字节串,再重新使用正确的编码转化成字符串。?
3.5 电子邮件中的字符串?
当一段 Text 或者 HTML 通过电子邮件传送时,发送的内容首先通过一种指定的字符编码转化成“字节串”,然后再把“字节串”通过一种指定的传输编码(Content-Transfer-Encoding)进行转化得到另一串“字节串”。比如,打开一封电子邮件源代码,可以看到类似的内容:?
Content-Type: text/plain;?
??????? charset="gb2312"?
Content-Transfer-Encoding: base64?
sbG+qcrQuqO17cf4yee74bGjz9W7+b3wudzA7dbQ0MQNCg0KvPKzxqO6uqO17cnnsaPW0NDEDQoNCg==?
最常用的 Content-Transfer-Encoding 有 Base64 和 Quoted-Printable 两种。在对二进制文件或者中文文本进行转化时,Base64 得到的“字节串”比 Quoted-Printable 更短。在对英文文本进行转化时,Quoted-Printable 得到的“字节串”比 Base64 更短。?
邮件的标题,用了一种更简短的格式来标注“字符编码”和“传输编码”。比如,标题内容为 "中",则在邮件源代码中表示为:?
// 正确的标题格式?
Subject: =?GB2312?B?1tA=?=?
其中,?
第一个“=?”与“?”中间的部分指定了字符编码,在这个例子中指定的是 GB2312。?
“?”与“?”中间的“B”代表 Base64。如果是“Q”则代表 Quoted-Printable。?
最后“?”与“?=”之间的部分,就是经过 GB2312 转化成字节串,再经过 Base64 转化后的标题内容。?
如果“传输编码”改为 Quoted-Printable,同样,如果标题内容为 "中":?
// 正确的标题格式?
Subject: =?GB2312?Q?=D6=D0?=?
如果阅读邮件时出现乱码,一般是因为“字符编码”或“传输编码”指定有误,或者是没有指定。比如,有的发邮件组件在发送邮件时,标题 "中":?
// 错误的标题格式?
Subject: =?ISO-8859-1?Q?=D6=D0?=?
这样的表示,实际上是明确指明了标题为 [0x00D6, 0x00D0],即 "?D",而不是 "中"。?
??
4. 几种错误理解的纠正?
误解:“ISO-8859-1 是国际编码?”?
非也。iso-8859-1 只是单字节字符集中最简单的一种,也就是“字节编号”与“UNICODE 字符编号”一致的那种编码规则。当我们要把一个“字节串”转化成“字符串”,而又不知道它是哪一种 ANSI 编码时,先暂时地把“每一个字节”作为“一个字符”进行转化,不会造成信息丢失。然后再使用 bytes = string.getBytes("iso-8859-1") 的方法可恢复到原始的字节串。?
误解:“Java 中,怎样知道某个字符串的内码?”?
Java 中,字符串类 java.lang.String 处理的是 UNICODE 字符串,不是 ANSI 字符串。我们只需要把字符串作为“抽象的符号的串”来看待。因此不存在字符串的内码的问题。?
原创文章,转载请保留或注明出处:http://www.regexlab.com/zh/encoding.htm]