目录
前言:
编码是信息从一种形式或格式转换为另一种形式的过程。解码是编码的逆过程。众所周知,计算机只能处理0和1(低电平与高电平),任何文本、数字、音频、图像等都转换为0和1的序列计算机才能处理。在计算机中,8个位(bit)作为一个字节,一个字节能产生2的8次方个0和1不同的组合,即最多能表示256中字符。由于计算机只能读懂0和1,所以就需要把人们熟悉的文本或数字转换为计算机能看懂的东西。因此,编码应用而生,科学家们为此制定了编码表。
1. 几种常见的编码表
1.1 ASCII编码
由于计算机是美国人发明的,他们设计了ASCII编码表(8位),把字母、数字、符号进行编码,一个字母、数字或符号占据一个字节。
例:字母A对应的ASCII编码:65(十进制)or 01000001(二进制,8bit)
ASCII编码局限性:只是解决了将英文转换为计算机能理解的语言问题。
随着计算机的普及,中国需要用计算机处理中文,同理,其它国家也需要用计算机处理本国的语言,因此不同的国家有了不同的编码格式,如gbk(一个字符占两个字节)等。但是这样会出现一个问题,不同的国家的编码不一致的情况下,如果在另外一个国家进行解码的话,会出现解码不正确,即乱码等。需要把所有的语言统一到一套编码里面,这样就不会出现乱码问题,因此Unicode编码(万国码)就出现了。
1.2 Unicode编码
Unicode编码是固定长度16位的,用两个字节表示一个字符,这样一共可以表示65536个字符。但这样要表示所有语言的字符还是远远不够的,因此Unicode4.0定义了一组附加字符编码,采用2个16位来表示。因此,在Unicode编码格式中,一个字符至少用2个字节表示(英文:2字节,汉字:三字节)。虽然这个编码满足了不同国家的语言要求,但是它不兼容ASCII编码,而且本来可以用一个字节表示的英文字母现在用了2个,占用了较多的空间和内存。所以,utf-8编码诞生了。
1.3 UTF-8编码
UTF-8也是一种万国码,兼容ASCII编码,由此我们可以推断UTF-8的编码长度是可变的,一个字符的长度可能是1个字节,2个字节,3个字节或者4个字节。ASCII编码中每个字符的编码在UTF-8中是完全一样的。
2.python3的编码方式
2.1 字符串和字符流
首先我们要明白字符串(str)和字符流(bytes)的区别:
- 字符串:str类型,用于程序内部,内存中
- 字符流:bytes类型,用于网络传输,保存文件
python3程序中的字符串默认为utf-8编码,也就是说python3字符串支持多语言。虽然python3字符串在内存中以Unicode表示,但是在网络上传输或者保存到磁盘的时候,需要把字符串(str对象)—>字节为单位的字节流(bytes对象)。
下面是输出python3中的默认编码utf-8:
下面是windows的默认编码gbk:
活动代码页对应下图的936:中国-简体中文(GB2312),所以我的windows系统的编码为gbk
str类和bytes类有着一模一样的方法列表,最大的区别就是encode()和decode(),即编码和解码
2.2 encode()方法
str类方法,以指定的编码格式编码str对象,返回bytes对象,默认编码方式为utf-8。
2.3 decode()方法
bytes类的方法以指定编码格式(与编码encode()所用的格式保持一致)解码bytes对象,返回str对象。
注意:如果本来就是str对象,则不能decode解码了,因为已经被解码成str了。同样,如果是bytes对象,则不能进行encode编码,了,否则会报错。
3. 区分以下编码
- 系统默认编码:windows简体中文,默认编码为gbk。如果将超过gbk范围的utf-8写入系统的txt文件,会报错,应该将utf-8码encode为bytes在写入。
- 编辑界面编码:编辑界面编码默认为
ASCII
,即写的程序语句默认是ASCII
,但一旦涉及到ASCII
不能表示的,就隐形转化为系统默认编码。程序中的字符串默认编码为Unicode
,也就是内存中的编码格式。 - 运行界面编码:cmd中运行程序,默认显示文本的编码是
ASCII
,一旦超出范围就隐式转换为系统编码。
pycharm运行界面的默认编码是utf-8
。所以有时在pycharm中print
没问题的字符串,到cmd中print
就会出问题。 - 代码文件编码:代码文件(py文件)本身也是文本,它也需要在硬盘或者其他载体上保存,默认编码为系统编码。这样的话,一旦py文件复制到其他系统中,就会出问题(乱码)。
- 读入文件编码:当从网络和硬盘读入文件时,实际上读到的是字节流。硬盘读入文件的默认编码方式是系统编码方式,当出现超过
gbk
范围的字节出现,会报错。网络读入文件时,因为读入的是字节,不会报错,但一旦print
时就会报错。
所以,如果不能按照读入文本的编码方式转化为Unicode
,就会出问题。 处理方式:因为read()
没有编码方式参数,只能读入bytes,然后再解码为Unicode
或者其他编码方式。这时需要先判断读入内容的编码方式,用chardet
的detect()
方法,接收bytes类型的参数,返回一个结果字典,包含编码方式和新都区间。
- 写出文件编码:如果想将文本直接以
Unicode
码保存到文件,用encode('unicode-escape')
转化为bytes,写入文件。