Java – 字符编码详解
简介
本篇文章讲解计算机当中的字符编码原理,及乱码原因的讲解。
字符集
在计算机中,任意数据都是以二进制的形式来存储的,从计算机的容量讲起,计算机的容量计量单位有很多,ZB->PB->TB->GB->MB->KB->B->Bit
计算机中最小存储单元为字节(B),一字节由8个比特(Bit)组成,每个Bit都是0或1的二进制数表示。
ASCII字符集
为了计算机能表示字母,在美国,他们开明了一种编码,叫ASCII码表,ASCII码表由1个字节存储,规则是,第一个Bit位为0,后面的Bit位可以从0~1
00000000 ~ 01111111
因此,ASCII 码表一共可以表示 128 个字母,关于ASCII码表的内容,在这里不进行阐述。
GB2312字符集
对于中国来说,只有128个存储量的ASCII码表是远远不够的,所以中国在1980年,制定了属于中国使用的码表 GB2312 .
GB2312 包含了 6763 个简体汉字,和 7445 个图形字符,但是GB2312 只包含了简体汉子,对于台湾等繁体字,在GB2312中没有包含。
BIG5字符集
因为GB2312码表中,并不包含繁体字,对于台湾而言,他们急需要一个码表,来表示台湾的繁体字,所以台湾地区在1984年实施了BIG5字符集,其中共收录13053个中文字。
GBK字符集
为了解决简体和繁体字的码表统一,中国在2000年3月17日发布新的中文字符集,其中包含了 21003 个汉字,包含GB13000-1标准中的全部中日韩汉字,和BIG5编码中的所有汉字。
ANSI字符集
对于Windows操作系统而言,每个国家都有他们对应的语言,也有他们对应的字符集,因此微软为了解决多国字符集的问题,把字符集统称为ANSI字符集
Unicode字符集
因为全世界每个国家都给自己制定了属于自己的字符集,这样零散的字符集不利于软件信息的交流,于是在1990年美国成立统一码联盟(Unicode组织),置力于把所有国家的字符集都收集到一个字符集中,成为【万国码表】,于1994年发布1.0版本,目前还在更新字符集中。
字符存储规则
我们知道ASCII码,使用1字节进行存储字母,最多能表示128个字符,所以对于不同字符集而言,它们存储一个字符所需要的字节数是不一样的。
GB2312 和 GBK 编码规则
对于中国而言,字符数是非常多的,如果像ASCII码表一样,使用1字节来存储是远远不够
所以中国在研发字符集的时候,规定了,在GBK和GB2312字符集中,每一个字符使用 2 个字节进行存储表示,字节的第一个Bit必须为1,这与ASCII码中的第一个Bit必须为0作为区分,使计算机能识别出来,何时使用ASCII码来解码,何时使用GBK码来解码。
其存储的范围在
00000000 00000000 ~ 11111111 11111111
其中,GBK和GB2312兼容ASCII字符集,所以0开头的,就是字母,1开头就是中文。
Unicode编码规则
对于Unicode而言,Unicode也有需于它的编码规则,因为它包含了全世界所有国家的字符,因此,它需要更多字节来存储一个字符。Unicode 提出了三种编码规则
UTF-16
在开始时候,Unicode制定了UTF-16编码规则,UTF-16 使用 2~4 个字节进行存储,也就是说,它的存储范围在
00000000 00000000 ~ 11111111 11111111 11111111 11111111
这对于中文而言是非常好的,但是对于英文而言,每一个英文至少都要占用2个字节,这显然是非常浪费存储空间的。
UTF-32
UTF-32 是固定使用 32 位 4 个字节来存储字符的,其范围在
00000000 00000000 00000000 00000000 ~ 11111111 11111111 11111111 11111111
可想而知,UTF-32是非常浪费存储空间的,尤其是英文字母。
UTF-8
对于前两种编码方式而言,都太过浪费存储空间了,所以现在基本上不怎么使用,但是用的最多,就是 UTF-8.因为 UTF-8 所使用的是 1~4 个字节来保存,其范围在
00000000 ~ 11111111 11111111 11111111 11111111
其中,为了让计算机区分什么时候读1个字节,什么时候4个字节,UTF-8做出以下规定
0xxxxxxxx 表示一个字节表达一个字符
110xxxxx 10xxxxxx 表示读两个字节表达一个字符
1110xxxx 10xxxxxx 10xxxxxx 表示读三个字节表达一个字符
11110xxxx 10xxxxxx 10xxxxxx 10xxxxxx 表示读四个字节表达一个字符
计算机通过识别前面的规则来判定需要读几个字节来表示一个字符。
其中,中文字使用3个字节表示,英文字母使用1个字节表示
乱码的产生
乱码的产生有两种可能,
一种是中文字需要2个或3个字节来存储,计算机在读取的时候,未完整读取所有字节。
另一种是字符编码有误。
读取未完整
举例子,一个中文字,在GBK(包括GB2312,下同)字符集中,是由2个字节进行存储的,如果计算机只读出1个字节,那么它所表示的字符,将不存在。
字母【a】
01100001
中文【汉】
10111010 10111010
当计算机取出字母 a 的字节时,转换二进制得出十进制 97,对比ASCII码表中的97,得出字母【a】.
当计算机以同样的方式读取中文字【汉】时,若计算机只读一个字节,那么转换二进制得出十进制为 -57 ,这在ASCII码中,并不能查到对应的字母,因而乱码,或不显示。
字符编码错误
这里使用GBK和UTF-8作举例
UTF-8中的【汉】
11100110 10110001 10001001
GBK中的【汉】
10111010 10111010
当计算机采用 GBK 字符集进行解码UTF-8中的【汉】时,会出取前两位字节,和最后一个字节作为分别计算,得出结果 59057 和 -119
通过在 GBK 码表中查找 59057 的字为【姹】,而-119 在GBK中不存在,因此最后得出的结果为【姹?】
这就是乱码的由来。
共有 0 条评论