字符串是Python中最经常使用的数据类型,并且不少时候你会用到一些不属于标准ASCII字符集的字符,这时候代码就极可能抛出UnicodeDecodeError: 'ascii' codec can't decode byte 0xc4 in position 10: ordinal not in range(128)异常。这种异常在Python中很容易遇到,尤为是在Python2.x中,是一个很让初学者费解头疼的问题。不过,若是你理解了Python的Unicode,并在编码中遵循必定的原则,这种编码问题仍是比较容易理解和解决的。python
字符串在Python内部的表示是unicode编码,所以,在作编码转换时,一般须要以unicode做为中间编码,即先将其余编码的字符串解码(decode)成unicode,再从unicode编码(encode)成另外一种编码。可是,Python 2.x的默认编码格式是ASCII,就是说,在没有指定Python源码编码格式的状况下,源码中的全部字符都会被默认为ASCII码。也由于这个根本缘由,在Python 2.x中常常会遇到UnicodeDecodeError或者UnicodeEncodeError的异常。编码
Unicode是一种字符集,它为每一种现代或古代使用的文字系统中出现的每个字符都提供了统一的序列号,规定了符号的二进制代码,但没有规定这个二进制代码应该如何存储。也就是说:Unicode的编码方式是固定的,可是实现方式根据不一样的须要有跟多种,常见的有UTF-八、UTF-16和UTF-32等。设计
为了可以处理Unicode数据,同时兼容Python某些内部模块,Python 2.x中提供了Unicode这种数据类型,经过decode和encode方法能够将其它编码和Unicode编码相互转化,但同时也引入了UnicodeDecodeError和UnicodeEncodeError异常。。code
Python中常见的几种编码异常有SyntaxError: Non-ASCII character、UnicodeDecodeError和UnicodeEncodeError等。下面依次举例说明一下:utf-8
这种异常最不容易出现,也最容易处理,主要缘由是Python源码文件中有非ASCII字符,并且同时没有声明源码编码格式,例如:ci
s = '中文' print s # 抛出异常
这个异常有时候会在调用decode方法时出现,缘由是Python打算将其余编码的字符转化为Unicode编码,可是字符自己的编码格式和decode方法传入的编码格式不一致,例如:unicode
#!/usr/bin/python # -*- coding: utf-8 -*- s = '中文' s.decode('gb2312') # UnicodeDecodeError: 'gb2312' codec can't decode bytes in position 2-3: illegal multibyte sequence print s
上面这段代码中字符串s的编码格式是utf-8,可是在使用decode方法转化为Unicode编码时传入的参数是‘gb2312’,所以在转化的时候抛出UnicodeDecodeError异常。还有一种状况是在encode的时候:字符串
#!/usr/bin/python # -*- coding: utf-8 -*- s = '中文' s.encode('gb2312') # UnicodeDecodeError: 'ascii' codec can't decode byte 0xe4 in position 0: ordinal not in range(128) print s
错误的使用decode和encode方法会出现这种异常,好比:使用decode方法将Unicode字符串转化的时候:get
#!/usr/bin/python # -*- coding: utf-8 -*- s = u'中文' s.decode('utf-8') # UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128) print s
固然,除了上面列出的几种出现异常的状况以外还有不少可能出现异常的例子,这里就不在一一说明了。源码
对于以上的几个异常,有如下几个处理的方法和原则。
在PEP 0263 -- Defining Python Source Code Encodings中提出了对Python编码问题的最基本的解决方法:在Python源码文件中声明编码格式,最多见的声明方式以下:
#!/usr/bin/python # -*- coding: <encoding name> -*-
其中是代码所须要的编码格式,它能够是任意一种Python支持的格式,通常都会使用utf-8的编码格式。
u'中文'
替代 '中文'
str1 = '中文编码' str2 = u'中文编码'
Python中有以上两种声明字符串变量的方式,它们的主要区别是编码格式的不一样,其中,str1的编码格式和Python文件声明的编码格式一致,而str2的编码格式则是Unicode。若是你要声明的字符串变量中存在非ASCII的字符,那么最好使用str2的声明格式,这样你就能够不须要执行decode,直接对字符串进行操做,能够避免一些出现异常的状况。
Python中出现这么多编码问题的根本缘由是Python 2.x的默认编码格式是ASCII,因此你也能够经过如下的方式修改默认的编码格式:
import sys sys.setdefaultencoding('utf-8')
这种方法是能够解决部分编码问题,可是同时也会引入不少其余问题,得不偿失,不建议使用这种方式。
最后分享一个终极原则:decode early, unicode everywhere, encode late,即:在输入或者声明字符串的时候,尽早地使用decode方法将字符串转化成unicode编码格式;而后在程序内使用字符串的时候统一使用unicode格式进行处理,好比字符串拼接、字符串替换、获取字符串的长度等操做;最后,在输出字符串的时候(控制台/网页/文件),经过encode方法将字符串转化为你所想要的编码格式,好比utf-8等。
按照这个原则处理Python的字符串,基本上能够解决全部的编码问题(只要你的代码和Python环境没有问题)。。。
额,最后一个方法,升级Python 2.x,使用Python 3.x版本。。这样说主要是为了吐槽Python 2.x的编码设计问题。固然,升级到Python 3.x确定能够解决大部分由于编码产生的异常问题。毕竟Python 3.x版本对字符串这部分仍是作了至关大的改进的,具体的下面会说。。。。
在Python 3.0以后的版本中,全部的字符串都是使用Unicode编码的字符串序列,同时还有如下几个改进:
因此,对于Python 3.x来讲,编码问题已经再也不是个大的问题,基本上不多遇到上述的几个异常。关于Python 2.x str&unicode和Python 3.x str&bytes的更多说明和对比,你们能够看一下:Python中字符编码的总结和对比
PS: 该文章转自个人博客:Python的中文编码问题
Over!