在阅读本文之前,相信你一定会有以下的疑问。
A.2进制、4进制、8进制、10进制、16进制,计算机到底是用哪种进制?
B.1kb 是1000字节?1000比特?还是1024?
C.计算机表示的数,什么时候是2进制表示?什么时候是其他进制表示的?
D.为什么有各种各样的编码?相互之间有何区别?
E.网页上的数据为utf-8编码。获取其数据后,直接写入到txt中,写入的是bit流?
F.这种bit流是什么方式表示的?16进制?8进制?
G.如果遇到两种编码的文件,其数据放到一起之后,难道应该分别进行编码解码?
--------------------------------------------------------------------------------------------------
1.计算机底层使用哪种进制?
(1)计算机内部是由集成电路这种电子部件构成的,电路只可以表示两种状态:电压高低、电流有无、电路通电断电。
(2)两种状态更稳定,也更容易区分。
(3)容易实现逻辑运算。
综合以上特性,计算机内部只能处理二进制。因此,无论最后以何种方式表示这个二进制代表的数,底层的计数方式为二进制!
2.字节与比特?
进制是按照进位方式计数的数制系统,进位方式计数含有基数和位权这两个参数。
二进制数 110 表示 1*2^2 + 1*2^1 + 0*2^0 = 6 1、1、0为基数 位权为2^2、2^1、2^0
底层 11111111 —— 可以使用 255(十进制)表示、 也可以使用 FF(16进制)、甚至是四进制3333
由此可以衍生出各个进制对数的表示。但考虑到计算机内部处理的其实是二进制,因此,我们以此为入口进行分析。
1位的二进制数范围在0-1(0-1)
2位的二进制数范围在0-3(00-11)
3位的二进制数范围在0-7(000-111)
4位的二进制数范围在0-15(0000-1111)
8位的二进制数范围在0-255(00000000-11111111)
当要表示的数逐渐变大的时候,以二进制方式计数的话,位数将会逐渐增多。内部计算机中占用的“格子”也会增加。计算机中,每1位二进制数所占的“格子”叫做bit(比特),八个bite构成一个Byte(字节)。
3.计算机中数据的表示?
计算机存储信息的基本单位是“字节”即Byte。一个Byte=8bit
即一个字节等于八个二进制位。表示数的范围为0-255
字节这个单位在实际使用中实在是太小的。常用的比字节大的单位还有:
1KB(千字节)=1024Byte
1MB(兆字节)=1024KB
1GB(吉字节)=1024MB
1TB(太字节)=1024GB
之所以之间倍数为1024,让我们来设想一下某人让 1 KB = 1000 Byte。
然后计算机会说:“有个问题想不通?1 KB 为什么要等于 1111101000 Byte???为什么不能等于 10000000000 Byte 啊????” k是倍数的简称,也是考虑到2进制10000000000的1024,所以不代表1000。
底层原理是以二进制来表示实际的数,而二进制的位权是以8位bit的字节进行存储,因此在实际的数字上,要么是8位、要么是16位、要么是32位,对应的就是一个字节、两个字节、三个字节。
4.编码问题详解
UnicodeEncodeError: 'gbk' codec can't encode character '\u27a2' in position 119: illegal multibyte sequence
UnicodeEncodeError: 'gbk' codec can't encode character '\xf4' in position 264: illegal multibyte sequence
UnicodeEncodeError: 'gbk' codec can't encode character '\ufeff' in position 277: illegal multibyte sequence
UnicodeEncodeError: 'gbk' codec can't encode character '\u2122' in position 212: illegal multibyte sequence
相信使用python的各位大胸弟都会遇到类似的问题,尤其是在mac上码好的代码,放到windows下,突然出现以上的错误。心态绝对会爆炸。
带着这个问题,我们来研究一下编码问题。
(1)编码、解码
encode字面意思:编码,编制成计算机语言。
decode字面意思:解码,分析及译解电子信号,找出实际意思。
第一部分我们已经知道,一个字符计算机底层数据是以二进制的bit流表示的。一般而言,表示这个bit流采用16进制方式。如:
str ='辣条'
print(str.encode())
输出结果为:b'\xe8\xbe\xa3\xe6\x9d\xa1' 其中的“\x” 表示十六进制。
那么当出现b'\xe8\xbe\xa3\xe6\x9d\xa1'的时候,它代表的是什么?这时候就用到了编码方式。
当遇到这样一串bit流,就需要找出正确的密码本,从密码本中分析电子信号,找出真实意思。
(2)密码本(各种编码及之间的关系)
https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/001431664106267f12e9bef7ee14cf6a8776a479bdec9b9000
由于计算机是美国人发明的,因此,最早只有127个字符被编码到计算机里,也就是大小写英文字母、数字和一些符号,这个编码表被称为ASCII编码,比如大写字母A的编码是65,小写字母z的编码是122。
但是要处理中文显然一个字节是不够的,至少需要两个字节,而且还不能和ASCII编码冲突,所以,中国制定了GB2312编码,用来把中文编进去。
你可以想得到的是,全世界有上百种语言,日本把日文编到Shift_JIS里,韩国把韩文编到Euc-kr里,各国有各国的标准,就会不可避免地出现冲突,结果就是,在多语言混合的文本中,显示出来会有乱码。
因此,Unicode应运而生。Unicode把所有语言都统一到一套编码里,这样就不会再有乱码问题了。
Unicode标准也在不断发展,但最常用的是用两个字节表示一个字符(如果要用到非常偏僻的字符,就需要4个字节)。现代操作系统和大多数编程语言都直接支持Unicode。
I 0049
t 0074
' 0027
s 0073
0020
知 77e5
乎 4e4e
日 65e5
报 62a5
以上就是“It's 知乎日报” unicode字符集的编码表。统一成Unicode编码后,当出现编码后的数据,我们也可以将其翻译出它的实际意思。当然,在找出其真实的意思之前,还有一步,那就是翻译的规则是什么?
unicode是一个字符集,里面几乎包含了目前世界上已知的所有字符,且该字符集将二进制代码和字符形成一一映射,即一个字符对应且只对应一个二进制代码,反过来,一个二进制代码对应且只对应一个字符。如果我们有一个字符,那么通过Unicode字符集很容易找到该字符对应的二进制码,但是,反过来,可能会出现混乱。
用通信理论的思路可以理解为:
unicode是信源编码,对字符集数字化;
utf8是信道编码,为更好的存储和传输。
新的问题又出现了:如果统一成Unicode编码,乱码问题从此消失了。但是,如果你写的文本基本上全部是英文的话,用Unicode编码比ASCII编码需要多一倍的存储空间,在存储和传输上就十分不划算。
所以,本着节约的精神,又出现了把Unicode编码转化为“可变长编码”的UTF-8编码。UTF-8编码把一个Unicode字符根据不同的数字大小编码成1-6个字节,常用的英文字母被编码成1个字节,汉字通常是3个字节,只有很生僻的字符才会被编码成4-6个字节。如果你要传输的文本包含大量英文字符,用UTF-8编码就能节省空间。
ASCII编码 ——>(GB2312、Shift_JIS、Euc-kr。。。各种冲突)——>unicode全世界语言整合到一起——>UTF-8/UTF-16
一句话,utf8是对unicode字符集进行编码的一种编码方式。
(3)字符串
在python3.6中,字符串'辣条'字符编码方式为unicode,unicode字符集的编码方式为utf-8。所以python3.6中,字符串'辣条'的默认编码方式utf-8。
可以理解utf是对unicode字符集的编码方式,就像 ascall码,但是gb2312,gbk,iso-8859-1这些不但是字符集也是编码方式。
str = '辣条'
print(str.encode('utf-8'))