Python 编码问题
最近在使用python对中文进行处理的时候,发现比处理英文复杂的多,中间遇到各种问题,由于对编码问题一直模糊不清导致走了很多的弯路,所以花了点时间整理了下python中的编码问题。在理解Python 中的编码问题之前需要了解编码的一些基本概念。
字符概念
字符是各种文字和符合的总称,也就是我们在屏幕看到的实体化的文字。
字符集是字符组成的集合,通常是以二维表的形式存在的,常常是字符和字符所对应存储的形式。例如有
ASCII
字符集、Unicode
、utf-8
字符集。字符编码: 字符是以二进制比特流的形式存储在计算机中, 字符编码就是把字符集转化为二进制码存储在计算机中。或者说让计算机进行识别
编码方式
不同的字符集都会对应一套字符编码方式,常见的有ASCII
码,Unicode
码、GBK
码。世界上存在多种编码方式,同一个二进制数字可以被解释成不同的符号。因此想打开一个文件必须要知道文件的编码方式,否则用错误的编码方式打开就会产生乱码。
ASCII
码:英语中字符较少,共有128个字符,ASCII
码美国采用基于拉丁文的一套编码系统,用于显示现代英语、阿拉伯数字和控制字符。采用7位表示一个字符。一个字节是八位,最高位为0。Unicode
码:世界上有不同语言的字符,Unicode
码包含了所有的的字符,每一个字符都被编码成一个二进制代码。Unicode
只是个符号集,只规定符号的二进制码,却没有规定该如何存储。常用的是用两个字节表示一个字符,如果是英文的话这种编码方式存储同样的文件所需要的存储空间比较大。utf-8
码: 是Unicode
的一种实现方式, 针对Unicode
的可变长度字符编码。使用前缀码来实现自己长度的变化,英语字符继续使用用一个字节表示,中文则可以使用三个字节进行表示。避免了Unicode
浪费存储空间。GBK
码:汉字内码扩展规范,是中国制定的,GBK
的文字编码 采用都是双字节的方式。包含了全部的中文,而utf-8
包含了世界上所有的字符,通用性较好。utf-8
和Unicode
的关系:Unicode
分为编码方式和实现方式,编码方式和ISO 10646通用字符集的概念相对应。一个字符的Unocode
码是确定的,但是在实际的传输存储过程中,根据不同的情况实现方式不同。Unicode
的实现方式成为Unicode
转换格式(Unicode Transformation Format, 简称UTF
),GBK也可以看做是Unicode
的一种实现方式,所以当GBK和UTF相互转换时,需要先转换为Unicode。
python 编码问题
目前计算机通用的字符编码工作方式:
在计算机内存中,统一使用Unicode
编码,当需要保存到硬盘或者需要传输的时候就转换为utf-8
编码。
源码中使用中文字符
.py
文件python 2.x默认采用的是ASCII编码,当文件中出现中文字符时就会出现SyntaxError: Non-ASCII character '\xe4'
错误。一般解决办法为在头文件加上#_*_coding=utf-8
,当对.py
文件存储时就会采用utf-8
编码格式。这样就能正确显示中文字符。而python 3.x
默认的编码方式采用的是utf-8
,直接就能正常显示中文字符
<type,str>
和<type,unicode>
的区别
str
是字节串,由Unicode
经过编码(encode
)后的字节组成的,也就是把字符串看作是字节的序列,而<type 'unicode'>
将字符串看作是字符的序列,单个字符可能占用多个字节,字节相对于字符,存储层次更低一些。
中文字符前面加上u
表示的是Unicode
字符串,如果想要把str
字符串转化为Unicode
时要使用decode
函数,当需要把Unicode
转换为str
时需要采用encode
函数 。例如下面一段代码
>>> s = 'str'
>>> type(s)
<type 'str'>
>>> type(s.decode())
<type 'unicode'>
>>> s = u'str'
>>> type(s)
<type 'unicode'>
>>> type(s.encode())
<type 'str'>
编码方式转换
python中内建函数Unicode()
是讲一个str
类型的字符串转变成一个Unicode
对象。
python中的解码函数decode()
是用来把以其它编码方式编码的字符串转化为Unicode
类型,例如把utf-8
类型的字符串转换为Unicode
字符串:str.decode("utf-8")
python中的函数encode()
是把Unicode
类型转换为其它编码方式,例如转换为str
类型:encode("utf-8")
在python中如果想实现不同编码方式的转变,需要先解码(decode
) 为Unicode
类型,再通过编码(encode
)转换为其它编码方式。例如把utf-8
转换为GBK
的编码方式:str.decode("utf-8").encode("GBK")
.
如果直接转换为GBK
:str.encode("GBK")
就会抛出下面的异常:
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe4 in position 0: ordinal not in range(128)
这是因为python
会自动先把str解码为Unicode
再编码为GBK
,而我们没有指定解码方式,此时python会自动采用ASCII
码进行解码,所以会出现这种错误。
python
处理中文字符的流程
python2.x 内部处理字符串时统一采用的是Unicode
,所以python
处理字符串的流程一般为:
- 将需要处理的字符串解码(
decode
函数)为Unicode
字符串,此时应该注意字符串或者文件本身的编码的类型,要以正确的方式进行解码,解码时需要与编码方式相对应 - 在python内部处理时统一采用
Unicode
字符串进行操作,在python内部进行处理不要轻易把字符串转其他编码方式 - 输出和存储时使用
encode
函数编码为所需要的编码方式