看完这个,再也不怕python3的乱码了。

在阅读本文之前,相信你一定会有以下的疑问。

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'))

你可能感兴趣的:(看完这个,再也不怕python3的乱码了。)