常见的几种字符集

github地址: https://github.com/longyu109

 

常见的字符集有ASCII码,Unicode码

常见的编码方式有 ISO-8859-1,GB2312,GBK,UTF-8,UTF-16

注意:下面图片中char[]的每个字符的码值都是Unicode。编码也就是将Unicode码值映射成其他编码,用于存储或者网络传输。

首先我们来看下ISO-8859-1编码

字符串"I am 君山" 用ISO-8859-1编码,编码结果如图所示

                      常见的几种字符集_第1张图片

可以看出,7个char字符经过ISO-8859-1编码转变成7个byte数组,ISO-8859-1是单字节编码,中文“君山” 被转化成值是3f的byte(编码大于一个字节的字符全部使用3f表示)。3f也就是"?"字符,所以经常会出现中文变成"?",很可能就是错误地使用了ISO-8859-1这个编码导致的。中文字符经过ISO-8859-1编码会丢失信息,通常我们称之为“黑洞”,它会把不认识的字符吸收掉,转变为3f,也就是“?”。由于现在大部分基础的java框架或系统默认的字符集编码都是ISO-8859-1,所以很容易出现乱码问题。

按照GB2312编码

字符串"I am 君山" 用GB2312编码,编码结果如图所示

常见的几种字符集_第2张图片

GB2312对应的Charset是sun.nio.cs.ext.EUC_CN,而对应的CharsetDecoder编码类是sun.nio.cs.ext.DoubleByte,GB2312字符集有一个char到byte的码表,不同的字符编码就查这个码表找到每个字符的对应的字节,然后拼接成byte数组。查表的规则如下:

c2b[c2bIndex[char>>8]+(char&0xff)

如果查到的码位值大于0xff则是双字节,否则是单字节。双字节高8位作为第一个字节,低八位作为第二个字节,如下代码所示:

 

if(bb>oxff){
        if(dl-dp<2) return CoderREsult.OVERFLOW;
        da[dp++]=(byte)(bb>>8);
        da[dp++]=(byte)bb;
}else{
         if(dl-dp<1) return COderResult.OVERFLOW;
         da[dp++]=(byte)bb;
}

 

可以看出,前5个字符经过编码后仍然是5个字节,而汉字被编码成双字节,GB2312只支持6763个汉字,所以并不是所有汉字都能够用GB2312编码。

按照UTF-16编码

字符串"I am 君山" 用UTF-16编码,编码结果如图所示

常见的几种字符集_第3张图片

用UTF-16编码将char数组放大了一倍,单字节范围内的字符在高位补0变成两个字节,中文字符也变成两个字节。从UTF-16编码规则来看,仅仅将字符的高位和低位进行拆分变成两个字节,特点是编码效率非常高,规则很简单。由于不同处理器对2字节处理方式不同,Big-endian(高位字节在前,低位字节在后)或Little-endian(低位字节在前,高位字节在后)编码,在对字符串进行编码时需要指明到底是Big-endian还是Little-endian,所以前面有两个字节用来保存BYTE_ORDER_MARK(BOM)值,UTF-16是用定长16位(2字节)来表示UCS-2或Unicode转换格式,通过代理来访问BMP之外的字符编码。

 

按照UTF-8编码

 

字符串"I am 君山" 用UTF-8编码,编码结果如图所示

常见的几种字符集_第4张图片

UTF-16虽然编码效率很高,但是对单字节范围内的字符也放大了一倍,这无形也浪费了存储空间,另外UTF-16采用顺序编码,不能对单个字符的编码进行校验,如果中间的一个字符码值损坏,后面的所有码值将受影响。而UTF-8不存在这些问题,UTF-8对单字节范围内字符仍然用一个字节表示,对汉字采用三个字节表示。

几种编码格式的比较

对中文字符几种编码格式都能处理,GB2312与GBK编码规则类似,但是GBK范围更大,它能处理所有汉字字符,所以GB2312与GBK比较,应该选择GBK。UTF-16与UTF-8都是处理Unicode编码,它们的编码规则不太相同,相对来说,UTF-16编码效率最高,字符到字节相互转换更简单,进行字符串操作也更好。它适合在本地磁盘和内存之间使用,可以进行字符和字节之间的快速切换,如Java的内存编码就采用UTF-16编码。但是它不适合在网络之间传输,因为网络传输容易损坏字节流,一旦字节流损坏将很难恢复,相比较而言UTF-8更适合网络传输,对ASCII字符采用单字节存储,另外单个字符损坏也不会影响后面的其他字符,在编码效率上介于GBK和UTF-16之间,所以UTF-8在编码效率上和编码安全性上做了平衡,是理想的中文编码方式。

你可能感兴趣的:(java)