一文帮你彻底弄懂编码/字节/字符

初入IT行业,如果不熟悉编码设置就会遇到一些所谓的乱码,它会莫名其妙出现在数据库的某条数据里,或者是在页面中,更多情况是在调试接口时对方会说,收到的请求参数是一串乱码或者返回得到的是一串乱码数据。带着这些问题,你就会开始查资料,哦,原来在某个地方声明下编码就行了,搞定!但对于编码本身,并不关心是怎么一回事,也懒得去关心,对于字节和字符也是一知半解,反正都是抱着能用就行的心态,可如果你等到真的搞清楚这些的时候,不管去学习哪一门语言都会通透许多。

本人整理了这方面的资料,加上自己的理解写了一篇小文,希望能帮到大家理解透彻些,10个人里面能看懂5个我就非常开心咯!

先说下编码

万物皆01

1字节(byte) = 8位(bit)
对于计算机来讲,它只能识别由0和1组成的二进制信息,不管是文件也好、字符串也好到了机器这都会变成由01组成的机器码,而对于java来讲,万物皆byte。

ASCII码

一个字节占8位,2的8次方256,1字节可以表示256种,针对这个,上个世纪60年代美国制定了一套方案,他们把英文字母以及常用的符号(都可称为字符,这个时候1字符=1字节)与二进制进行了关联,做了统一的规定,这个规定被称为是ASCII码(注意,ASCII只有128个,0-127,最高位为0,2的七次方=128,128到255被称为“扩展字符集”,主要是为了表示一些非美帝国家的字母和符号)。
在这里插入图片描述

ASCII码对于创造者美帝来说肯定够了呀,但是其他国家怎么办,尤其是像中国拥有将近10万个汉字的这种

GB2312/GBK/GB18030

于是聪明的中国人制定了一套属于自己的编码规范:规定一个小于127(十进制)的字符还是跟之前的意思一样,两个大于127的字符连在一起时就表示一个汉字,前者叫高字节,后者叫低字节,收录了6763个汉字以及682个特殊符号,看着不多但已经囊括了生活中最常用的所有汉字,原有的ASCII码里包含的符号也在里面,这些字符都占用两个字节,为避免与ASCII码冲突最高位设置不为0,这套汉字的编码方案被称为GB2312,是对ASCII的中文扩展。

但问题由来了,中华文化博大精深,区区两个字节能把所有汉字都表示清楚吗,答案肯定是不行的,所以后来对上述方案又进行了改进:规定只要第一个字符大于127的,都会被认定为是一个汉字的开始,不管后面跟了几个字符,可以表示的汉字达到了20902个,另有984个汉语标点符号、部首等,这套规定被称为GBK。

后面为了包含全部的汉字中国又进行了编码扩展,GBK扩展为GB18030,到现在GB18030编码的中文文字已经有七万多个汉字,甚至包含了少数民族文字。

各个编码的字节范围(了解下就行):

  • GB2312的第一个字节的值在0xB0到0xF7之间,第二个字节的值在0xA0到0xFE之间
  • GB2312的第一个字节的值在0x81到0xFE之间,第二个字节的值在0x40到0xFE之间
  • GB18030跟前两者不同,编码长度从2个字节变成1至4字节image.png

实际使用中GBK编码已经包含了常用的99.9%汉字,同时也对GB2312兼容,所以相比较另外两个编码,GBK使用会多一些。

编码巴比伦塔命题

中国人创造了属于自己的编码格式,那日本人、韩国人呢,他们肯定不会用我们创造出来的标准,傲娇的很,理所应当的也都各自制定了好几套符合自己国情的编码标准,自己国人用的是爽了,但不同国家编码标准放到互联网上简直就是一种灾难。

Unicode

为了解决以上问题,一个叫ISO(国际标准化组织)的组织出手了,他们制定了一套标准叫Unicode,这套标准包含了这个星球上所有的文字和符号,废除了地方性质的编码标准,真正做到了全球大统一

Unicode规划了17个平面,0-16,范围从0x0000到0x10FFFF(0x开头代表16进制),每个平面可以表示2``65536个字符,我们一般用到的是第0平面-基本多语言平面(Basic Multilingual Plane BMP,范围为0x0000-0xFFFF),其他的SMP(Supplementary Multilingual Plane)平面、SIP(Supplementary Ideographic Plane)平面、TIP(Tertiary Ideographic Plane)平面等“辅助平面”我们只要了解下就行了,如果想了解详细信息请出门右转维基百科

BMP非常大气的规定所有字符都用两个字节大小(从0x0000到0xFFFF)来表示,即UCS-2,最多可以表示65536个字符,包括英文字母这种本来只需要1个字节大小的,不管,因为在规定unicode时计算机的存储器得到了极大的发展,空间不再是问题。但值得注意的是unicode只是一个符号集,规定了如何编码但没规定如何存储,所以不能说unicode字符最后一定占用两个字节,它只是一种规范。比如一个“汉”字,unicode编码是6C49,既可以用4个ASCII码来表示和传输,也可以用三个UTF-8的连续编码 E6 B1 89来表示,一个字符的大小跟编码格式有关,跟规定的大小没有直接的关系,不知道这么讲你们能不能理解,所以说虽然unicode统一了字符定义,但在通信/存储方面双方还是要采取某一种编码格式,否则还是会出现兼容问题。

如果不理解Unicode都已经定义好了编码为什么就不能用来存储和通信呢?我举几个简单例子

  • 计算机是如何知道3个字节的代表是某一个字符而不是某三个字符?没有具体的规律可循啊
  • 英文字母和某些符号只需要一个字节大小就够了,如果像上面一样规定所有字符都用两个字节来表示,那不是浪费了一个字节的空间吗

看不懂上面的瞅下这个总结:Unicode只是定义了每个字符编号是多少(更多是文本意义上的),具体实现到计算机/网络里的存储/通信还是需要编码,尤其是互联网时代到来后。
**
还是不太理解,没关系,请继续往下看↓

UTF-8/UTF-16/UTF-32

它来了它来了!!!终于要讲解平常工作中用到最多的编码了,重点来了
上面讲到unicode还需要编码格式来定义,utf-8就是其中非常重要、使用非常广泛的一种。这种编码格式以8位为一个编码单位把抽象的字符规定翻译成了具体可以被用来存储和通信的字符,双方只要约定用这一种编码规定就不会出现乱码情况。

但是你以为UTF-8只是单纯为了编码约定吗,不是的,它还有另外一种重要功能:减少字符占用空间

问:咦?上面不是说不差计算机存储空间吗,怎么又要需要减少占用呢?
答:先不说存储空间,就讲讲通讯行为。Unicode出现的时候互联网不发达,没什么通讯行为,但后来发现数据需要传输了,那么数据包的大小对于传输效率显得尤为重要,比如传输一个10m大小的文件,因为编码问题变成了15m,那么是不是相当于传输速度下降了1/3?

举个栗子,有一个中文汉字占用两个字节,但英文字母不需要呀,它只需要一个字节大小就够了,多出来的一个字节不就浪费了吗?UTF-8有一个特性就是可变长度,可以用1-4个字节来表示一个字符,具体的大小根据实际情况来,这样子就可以有效减少字符占用空间,从而提高通讯效率,那么它是如何实现对不同的字符设定不同的长度呢

(接下来讲的内容牵涉到UTF8底层编码算法问题,有兴趣看一下,看不懂也没关系,不影响理解之前的知识点)

UTF-8是这么规定的:(x代表0或者1)

  • 只占一个字节的字符,8位字节第一位就是0

0 X X X X X X X

  • 占用2个字节的字符,第一个字节的是以110开头,第二个字节以10开头

1 1 0 X X X X X 1 0 X X X X X X

  • 占用3个字节的字符,第一个字节的是以1110开头,剩余字节都以10开头

1 1 1 0 X X X X 1 0 X X X X X X 1 0 X X X X X X

  • 占用4个字节的字符,第一个字节的是以11110开头,剩余字节都以10开头

1 1 1 1 0 X X X 1 0 X X X X X X 1 0 X X X X X X 1 0 X X X X X X

for example:
比如“严”字,我们在Unicode下找到它的编码是4E25,换成二进制是100111000100101,在下表中会发现它需要三个字节表示

Unicode符号范围UTF-8编码方式
十六进制二进制
00000000至0000007F0XXXXXXX
00000080至000007FF110XXXXX 10XXXXXX
00000800至0000FFFF1110XXXX 10XXXXXX 10XXXXXX
00010000至0010FFFF11110XXX 10XXXXXX 10XXXXXX 10XXXXXX

按照多位头部补0原则,“严”字在utf-8编码中的编码是11100100 10111000 10100101,这个是中文的编码方式,英文字母只需要一个字节就可以了,所以ASCII码的编码值跟在UTF-8中是相同的,没有什么变化。

联想下,为什么有时候会发现mysql数据库表是UTF-8的情况下里存emoji报错,因为在mysql中,utf8只占用三个字节,存储不了4个字节的emoji。

小结

从上面的说法里可以看出,GBK等编码跟unicode没有半毛钱关系,后者推翻了包括GBK/GB2312等地方性的编码标准,而UTF8等编码是为了翻译unicode字符设定的标准,等于说UTF-8出现乱码的概率不大(因为是针对unicode),UTF8所对应的unicode已经包含了绝大部分的常用字母、汉字以及符号,所以很多情况下我们用UTF-8会比较多,那么是不是说GBK和GB2312等编码没用了呢?不是的

还是占用空间大小问题,UTF-8为了兼容所有字符一定程度上也牺牲了对汉字的压缩,同样一个汉字,UTF-8至少需要3个字节,GBK则只需要2个,所以,在数据大部分都是中文的情况下采用GBK编码格式的会节省下不少空间。

思考,为什么中文在UTF-8编码中至少会占用3个字节,答题写在评论区

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值