编码实质就是0101序列翻译成我们人类能够看懂的东西
========================
ASCII 用后7位 最后一位保留了 总共128种字符
ASCII的扩展(EASCII):使用了最高位,扩展到256种,但是各国都有自己的标准
于是有了ISO/8859-1 重新定义了 160~255个字节
因为一个字节只能使用256个字符,对于亚洲国家来说不够
于是有了GB2312的双字节编码(2^16=65536种),又因为罕见字和繁体字没办法处理
于是有了GBK
各个国家的编码方式的不同,于是出现了Unicode
但是如果unicode以固定的长度存储,将会大大的浪费带宽和存储空间
于是出现了可变长的存储方案,UTF-8,UTF-16
如何表示unicode的编码,
比如“汉”是U+6C49,实质也是0101序列,那么如何翻译呢?
类比,unicode就像英语,然后各个国家翻译成自己的语言
各个国家表示的就是UTF-8,UTF-16等等,每种都有自己的翻译,然后对照Unicode表
Unicode用4个字节,表示了40多亿个字符(2^32),同时规定了和其他编码的映射关系,
所有的操作系统都支持Unicode,所有存到内存中的0101序列都是由Unicode来存储的。
比如和UTF-8的(翻译方式):
为了更好理解,上面这张表对应Unicode的范围转换成10进制:
0-127:---第一行
128-2047:---第二行
2048-65535:---第三行
65536-1114111 ---第四行
比如”好”对应的Unicode编码是597D,十进制为22909,对应的区间落在第三行,所以使用3个字节,
597D二进制表现为0101 1001 0111 1101
填充到第三行: 1110 0101 1010 0101 1011 1101
十六进制: e 5 a 5 b d
这里和a.encode(‘utf-8’)结果是一样的
所以当我们看见类型这样的字节时候应该这样反应(python3中使用utf-8):
这个例子是三个字节,对应格式是:1110xxxx 10xxxxxx 10xxxxxx
首先全部转化成二进制,剔除固定格式中的0101,只留下x,这个x组成的就是utf-8对应的unicode
UTF-8的编码规则:对于一个字节,直接是使用ASCII
对于需要N个字节的,第一个字节的前N为置为1,N+1位置为0,后边的每一个字节的前两位都置为10
结合到实际我们是如何使用UTF-8存储文件的,我们规定了一个文件hello.txt,编码使用UTF-8,内容只有“您好”两个字,首先查询Unicode的表结合UTF-8的规则,和上边一样对应的求出一串的0101001,同理“好”也是这样,这样就会以010100..的方式存储起来了。
在我们查看这个文件的时候,其实就是从内存中加载(一连串的0101001..),然后显示到屏幕上,因为原来我们是用UTF-8形式的01010存储起来的,那么读取的时候,应该使用UTF-8的规则去读取,如果用GBK或者别的规则去读取,就会乱码。
因为是一连串的0101,如何判断一个字符的分割?(假设已经知道他是UTF-8编码)
因为之前提到UTF-8的规则,N字节就设置前N为1,N+1为置为0,加载的时候以字节为单位(8位),比如加载了一个0xxxxx,我们就知道他占用一个字节,继续读取读到1110xxxx这样形式的,那么后边的两个字节会和这个组成一个翻译单元,去Unicode表中找到对应的字。这样就可以显示出来了
存储的过程实质就是将这个文件用二进制的形式存到硬盘上,那么如何编码这些010101,是由我们采用的编码来确定的。因为Unicode使用4个字节,可以表示所有的文字,
假设我们存储“你好”这个文本,对应unicode是u4f60u597d,他实际的存储空间就是8个字节(64位),
但是实际上,不会用这种方式来存储,很浪费空间。如果我们使用UTF-8表做下映射,可以减少存储空间,4f60对应十进制的20320,也是落在第三区间,因此使用3个字节,参考上面我们可以得出他用十六进制的编码为:
注意到 这样3个事实,
1。Unicode必须要用4个字节,因此前边要置为0
2。00 00 4f 60 00 00 59 7d 和 e4 bd a0 e5 a5 bd所表示的二进制是不一样的!
3。读取的时候,实际读取的是e4 bd a0 e5 a5 bd所表示的二进制字符流,操作系统事先知道了他使用了UTF-8编码,所以能够用UTF8的规则来读取。
比如:e二进制是:1110 ,那么接下来他会读取3个字节,e4 bd a0,转为2进制,去除第一个字节的1110,第二和第三个字节的10,能够得到另外的2进制串,
e4 bd a0 --->1110 0100 1011 1101 1010 0000 --->0100 1111 0110 0000-->4F60
这个4F60在Unicode表中对应的就是“你”,操作系统默认有一张Unicode表可供查询
本文参考了许多知乎上的回答:
Python 编码为什么那么蛋疼? - 刘志军的回答 - 知乎
Python 编码为什么那么蛋疼?www.zhihu.comPython 编码为什么那么蛋疼? - Alex-金角大王的回答 - 知乎
Python 编码为什么那么蛋疼?www.zhihu.com本人小白一枚, 如果错啦,请大神指出,谢谢啦~