`
nigel521
  • 浏览: 11458 次
社区版块
存档分类
最新评论

黑马程序员——字符编码

 
阅读更多

------- android培训java培训、期待与您交流! ----------


编码表的由来:
计算机只能识别二进制数据,早起由来是电信号。为了方便应用计算机,让它可以识别各个国家的文字,就将各个国家的文字用数字来表示,并一一对应,形成一张表。这就是编码表。
常见的编码表:
为什么出现占用7位,和占用8位的还有两字节的?
因为占7位的被ASCII率先使用了,占8位的被拉定码率先使用。到了中国这块,就是用两个字节的了。
ASCII:美国标准信息交换码。用一个字节的7位可以表示。
ISO8859-1:拉丁码表。欧洲码表,用一个字节的8位表示。
GB2312:中国的中文编码表。
GBK:中国的中文编码表升级版,融合了更多的中文文字符号。
Unicode:国际标准码,融合了多种文字。
所有文字都用两个字节来表示,Java语言使用的就是Unicode。
UTF-8:最多用三个字节来表示一个字符,最小使用一个字节。(全世界通用)。
编码: 字符串变成字节数组。

解码:字节数组变成字符数组。代码示例:
package encode;
import java.io.UnsupportedEncodingException;
public class CharacterEncode {
 public static void main(String[] args) throws Exception {
  String str = "你好";
  byte[] bytesGbk = str.getBytes("GBK");
  String strGbk = new String(bytesGbk,"iso8859-1");
  System.out.println(strGbk);
// 在用iso8859-1进行重新编码,再用GBK重新解码,输出结果是:你好
  byte[] bytesIso = strGbk.getBytes("iso8859-1");
  String str2 = new String(bytesIso,"GBK");
  System.out.println(str2);
//在用utf-8进行重新编码,再用GBK重新解码,输出结果是:锟斤拷锟?
  String strUtf = new String(bytesGbk,"utf-8");
  byte[] bytesUtf= strUtf.getBytes("utf-8");
  String strUtf2 = new String(bytesUtf,"gbk");
  System.out.println(strUtf2);
 }
// 为什么两次的结果差距那么大?
/*原因:
 * 因为utf-8编码表中有个区域是:如果找不到对应的字符,那么就到该区域找值也就是?(-17,-65,-67)。当你用GBK进行编码的时候,就会用那区域的
 * 对应的字节数值去到GBK中找字符。就找不到对应的字符了。
 * 而iso8859-1是一个字节对应一个字符。UTF-8和GBK都支持中文。
 * */
}
5.字符与编码的发展
 
  系统内码 说明   
阶段一 ASCII 计算机刚开始只支持英语,其它语言不能够在计算机上存储和显示。ASCII码一共规定了128个字符的编码,比如空格“SPACE”是32(二进制00100000),大写的字母A是65(二进制01000001)。这128个符号(包括32个不能打印出来的控制符号),只占用了一个字节的后面7位,最前面的1位统一规定为0。   
阶段二 ANSI编码(本地化) 为使计算机支持更多语言,通常使用 0x80~0xFF 范围的 2 个字节来表示 1 个字符。比如:汉字 '中' 在中文操作系统中,使用 [0xD6,0xD0] 这两个字节存储。不同的国家和地区制定了不同的标准,由此产生了 GB2312, BIG5, JIS 等各自的编码标准。这些使用 2 个字节来代表一个字符的各种汉字延伸编码方式,称为 ANSI 编码。在简体中文系统下,ANSI 编码代表 GB2312 编码,在日文操作系统下,ANSI 编码代表 JIS 编码。不同 ANSI 编码之间互不兼容,当信息在国际间交流时,无法将属于两种语言的文字,存储在同一段 ANSI 编码的文本中。   
阶段三 UNICODE(国际化) 为了使国际间信息交流更加方便,国际组织制定了 UNICODE 字符集,为各种语言中的每一个字符设定了统一并且唯一的数字编号,以满足跨语言、跨平台进行文本转换、处理的要求。Unicode当然是一个很大的集合,现在的规模可以容纳100多万个符号。每个符号的编码都不一样,比如,U+0639表示阿拉伯字母Ain,U+0041表示英语的大写字母A,U+4E25表示汉字“严”。需要注意的是,Unicode只是一个符号集,它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储。 

6.几种误解以及乱码产生的原因和解决办法。
 
  对编码的误解   
误解一 在将“字节串”转化成“UNICODE 字符串”时,比如在读取文本文件时,或者通过网络传输文本时,容易将“字节串”简单地作为单字节字符串,采用每“一个字节”就是“一个字符”的方法进行转化。 而实际上,在非英文的环境中,应该将“字节串”作为 ANSI 字符串,采用适当的编码来得到 UNICODE 字符串,有可能“多个字节”才能得到“一个字符”。 通常,一直在英文环境下做开发的程序员们,容易有这种误解。   
误解二 在 DOS,Windows 98 等非 UNICODE 环境下,字符串都是以 ANSI 编码的字节形式存在的。这种以字节形式存在的字符串,必须知道是哪种编码才能被正确地使用。这使我们形成了一个惯性思维:“字符串的编码”。 当 UNICODE 被支持后,Java 中的 String 是以字符的“序号”来存储的,不是以“某种编码的字节”来存储的,因此已经不存在“字符串的编码”这个概念了。只有在“字符串”与“字节串”转化时,或者,将一个“字节串”当成一个 ANSI 字符串时,才有编码的概念。 不少的人都有这个误解。 
第一种误解,往往是导致乱码产生的原因。第二种误解,往往导致本来容易纠正的乱码问题变得更复杂。
2.非Unicode程序在不同语言环境移植乱码
非 UNICODE 程序中的字符串,都是以某种 ANSI 编码形式存在的。如果程序运行时的语言环境与开发时的语言环境不同,将会导致 ANSI 字符串的显示失败。
3.网页提交字符串
当页面中的表单提交字符串时,首先把字符串按照当前页面的编码,转化成字节串。然后再将每个字节转化成 "%XX" 的格式提交到 Web 服务器。比如,一个编码为 GB2312 的页面,提交 "中" 这个字符串时,提交给服务器的内容为 "%D6%D0"。 在服务器端,Web 服务器把收到的 "%D6%D0" 转化成 [0xD6, 0xD0] 两个字节,然后再根据 GB2312 编码规则得到 "中" 字。 在 Tomcat 服务器中,request.getParameter() 得到乱码时,常常是因为前面提到的“误解一”造成的。默认情况下,当提交 "%D6%D0" 给 Tomcat 服务器时,request.getParameter() 将返回 [0x00D6, 0x00D0] 两个 UNICODE 字符,而不是返回一个 "中" 字符。因此,我们需要使用 bytes = string.getBytes("iso-8859-1") 得到原始的字节串,再用 string = new String(bytes, "GB2312") 重新得到正确的字符串 "中"。
4.从数据库读取字符串
通过数据库客户端(比如 ODBC 或 JDBC)从数据库服务器中读取字符串时,客户端需要从服务器获知所使用的 ANSI 编码。当数据库服务器发送字节流给客户端时,客户端负责将字节流按照正确的编码转化成 UNICODE 字符串。 如果从数据库读取字符串时得到乱码,而数据库中存放的数据又是正确的,那么往往还是因为前面提到的“误解一”造成的。解决的办法还是通过 string = new String( string.getBytes("iso-8859-1"), "GB2312") 的方法,重新得到原始的字节串,再重新使用正确的编码转化成字符串。
5.几种错误理解的纠正
误解:“ISO-8859-1 是国际编码?”
非也。iso-8859-1 只是单字节字符集中最简单的一种,也就是“字节编号”与“UNICODE 字符编号”一致的那种编码规则。当我们要把一个“字节串”转化成“字符串”,而又不知道它是哪一种 ANSI 编码时,先暂时地把“每一个字节”作为“一个字符”进行转化,不会造成信息丢失。然后再使用 bytes = string.getBytes("iso-8859-1") 的方法可恢复到原始的字节串。
误解:“Java 中,怎样知道某个字符串的内码?”
Java 中,字符串类 java.lang.String 处理的是 UNICODE 字符串,不是 ANSI 字符串。我们只需要把字符串作为“抽象的符号的串”来看待。因此不存在字符串的内码的问题。    

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics