深入浅出字符编码


首先先提几个问题:

1. 为什么计算机只能识别二进制?

因为计算机里是靠高电平和低电平来控制逻辑电路的,表示逻辑里面“真”和“假”,转化成数字表示就是1和0,符合二进制的数学逻辑,所以计算机底层是根据二进制来控制的。

这边可以参考编程漫画的一篇文章<<漫话:如何给女朋友解释为什么计算机只认识0和1?>>

2. 计算机里是怎么存储信息的?

计算机里的信息是存储在计算机存储器中的,存储器由无数个存储单元组成,每一个存储单元都有一个内存地址,每一个存储单元都是由8个高低电位(用bit表示)组成。也就是8个bit = 1byte,所以bit是计算机表示数据的基本单位,byte是计算机存储的基本单位。

这个好像是在<<程序是怎么跑起来的>>书中看的。

3. 我们有时候看到的16进制,在计算机里面发挥着什么样的作用?

我们知道计算机底层是用二进制表示的,那么16进制是来做什么的呢。
比如说二进制 1101111000,在计算机里存储是这样存储的 00000011 01111000,这样的话我们读写起来会很麻烦,但是把他们转换成16进制表示就是 03 78 ,16进制的1位刚好可以表示二进制的4位,这样用两位16进制数就能表示8位的2进制数,同时对比二进制表示长度缩短4倍,给读写带来很大的方便。但是他们在计算机底层是一样的,只是给用户的展现形式不一样。

使用16进制一方面缩短了二进制表示的长度,同时保持了二进制数的表达特点。

4. 我们经常看到“0x”是什么意思?

这是因为在一些高级语言比如 C,C++中,规定用“0x”开头来表示16进制。他们为什么要这么做呢?
其实就是为了区分你这个到底是16进制表示的还是其他意思。
比如字符11,如果表示的是十进制,那么就是数字“11”,如果表示的是二进制就是数字“3”,表示的是16进制就是数字“17”,所以为了区分,规定16进制都以“0x”开头。

5. 什么是字符编码,为什么要用到字符编码?字符集又是什么?

我们知道1个bit有2种状态(0和1),2个bit能表示4中状态,3个bit能表示8种状态,依此类推,计算机要表示更多的状态,就用更多的bit就行了,计算机基本存储单位是byte(字节),1byte=8bit,理论上1个字节可以表达256种状态,用每一种状态去表示1种字符,就可以表示256种字符。在计算机里表示的话就可以用二进制去表示字符。

人们通过约定来把二进制和人类字符对应起来,这种约定的对应关系就是字符集。
通过这种字符集进行编码就是字符编码。人们看到的是字符,把它转换成对应的二进制存储在计算机里,读取的时候再按照字符集进行转义就得到了字符。

字符编码过程就是通过一定的约定把人类语言转换成计算机可以识别的二进制语言。
256种状态是远远不能表示人类的所有字符的,但是他们都是以byte为单位进行扩展的。

6. ASCII码?

ASCII码字符集是由美国人制定的,它规定用7位二进制来表示128种字符,包含了大小写字母,数字,英文符号的二进制表示。
在计算机里至少需要用7bit来表示,最少需要1个字节来存储,开头用0来代替多出来的bit。

但是ASCII用来表示英文是足够了,但是像一些其他国家的字符就没办法表示了,所以用ASCII是不能用来编写汉字的。

7. GB2312和GBK?

上面说了ASCII码不能表示中文,不止是中文,别的国家的字符也没法表示,各个国家就制定了符合自己国家标准的字符集。
GB2312和GBK就是在这样的背景下产生的。
GB2312规定1个字符用2个字节表示,也就是16位的二进制来表示1个字符。GB2312最多可以容纳65536种字符。

但是这种字符集也只能满足自己国家的需要,国家之间没有一个统一的标准,就会导致用GBK编码的字符,用其他国家的字符编码解析就会出现乱码,导致不能通用。
不妨用notepad++去试一下,用GBK编码,用UTF-8打开,就会出现乱码的情况。

8. Unicode字符集?

Unicode 是为了解决传统的字符编码方案的局限而产生的,它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言、跨平台进行文本转换、处理的要求。
Unicode开始用2个字节来表示一个字符叫做UCS-2字符集。最多能表示65536个字符。
后来发展到UCS-4字符集,用4个字节来表示一个字符,范围从 0x0 - 0x10FFFF,理论上能容纳 1114112 个字符,已经上百万的数量级了。
对应关系参考Unicode字符集
Unicode字符集涵盖了世界上大多数的字符。如果大家都用这种字符集去编码,就可以解决字符编码不能通用的问题。

既然用Unicode去编码解码也是可以的,那为什么我们在编码的时候经常听到用UTF-8,UTF-16编码格式,却没听说Unicode编码格式。

9. UTF-8,UTF-16?

Unicode作为一种字符集,规定要用2个或者4个字节表示一个字符,它只声明了一个统一的字符集,但是没有规定字符编码的实现方式。那么我只要用我的实现方式能够跟字符集对应起来就可以了。UTF-8和UTF-16就是这样的实现方式。
首先Unicode表示的字符,至少需要2个或者4个字节,而用ASCII码表示英文只需要1个字节,如果都用2个字节或4个字节,会造成很大的空间浪费。

UTF-8就是一种以字节为单位的编码方式,它最大的特点就是可变的字节长度。

Unicode编码(十六进制)UTF-8 字节流(二进制)
000000-00007F0xxxxxxx
000080-0007FF110xxxxx 10xxxxxx
000800-00FFFF1110xxxx 10xxxxxx 10xxxxxx
010000-10FFFF11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

可以看出,ASCII码的字符范围完全对应Unicode的000000-00007F的字符范围,用UTF-8编码的话,原ASCII码的字符在000000-00007F范围内,会占用1个字节,中文符号在000080-0007FF范围内,占用2个字节,中文大多数在000800-00FFFF范围内,会占用3个字节,少数中文在010000-10FFFF范围,占用4个字节。

那么就有人会问,为什么中文汉字在Unicode中是2个字节,而用UTF-8编码反而要占用3个字节,这样值吗?
答案是值。

先说为什么中文用UTF-8编码要占用3个字节。 因为UTF-8要区分你在哪个Unicode范围内,在编码的时候要做个标记,比如单字节以0开头的二进制表示字符就在000000-00007F这个范围内,用同样的方法解析就能得到它的Unicode值。第一个以1110开头,第二个字节以10开头,第三个字节还是10开头,第四个字节不是以10开头,那就说明签前三个字节表示一个字符,并且Unicode范围在000800-00FFFF,拿到这三个字节除了开头部分组合起来就是一个16位的二进制,也就能找到他所对应的Unicode字符,这三个字节中,用来标记的开头部分就要占用一个字节。至于说值不值,看看编程代码里最多的字符是什么就清楚了。(我是这样理解的)

附:Unicode和UTF编码转换

10. 计算机是怎么知道文件按什么编码格式解释?

取决于你所指定的编辑器的编码格式。
比如使用notepad++指定用utf8格式编写的文件,保存到计算机。编辑器会将文件按照utf8的格式转成二进制存储在硬盘上。当你读取这个文件时,将二进制文件读取,再按utf8的格式进行翻译,展示成文字。
同样的文件可以用不同的编码格式来解释,说明了二进制文件是不变的,取决于读取文件的方式。指定不同的编码格式读取到的意思是不同的。

11. 所以字符到底是占用几个字节呢?

–>大小写英文字母英文符号数字中文符号大多数中文汉字生僻汉字(龠)
ASCII字符编码111---
GB2312222222
UTF-8111334
UTF-16222444
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值