注意:本文只是针对 python 2,在 python 3 中,编码方式与处理技巧有些许变化,具体请参考:php
Python 2 与 Python 3 的差别对比: http://my.oschina.net/leejun2005/blog/173553 html
在python源码中若是使用了中文字符,运行时会有错误,解决的办法是在源码的开头部分加入字符编码的声明,下面是一个例子:
#!/usr/bin/env python
# -*- coding: cp936 -*-
Python Tutorial中指出,python的源文件能够编码ASCII之外的字符集,最好的作法是在#!行后面用一个特殊的注释行来定义字符集:
# -*- coding: encoding -*-
根据这个声明,Python会尝试将文件中的字符编码转为encoding编码,而且,它尽量的将指定地编码直接写成Unicode文本。
注意,coding:encoding只是告诉Python文件使用了encoding格式的编码,可是编辑器可能会以本身的方式存储.py文件,所以最后文件保存的时候还须要编码中选指定的ecoding才行。python
>>> str = u"中文"
>>> str
u'\xd6\xd0\xce\xc4'
>>> str = "中文"
>>> str
'\xd6\xd0\xce\xc4'
u"中文"只是声明unicode,实际的编码并无变。这样子就发生变化了:
>>> str = "中文"
>>> str
'\xd6\xd0\xce\xc4'
>>> str = str.decode("gb2312")
>>> str
u'\u4e2d\u6587'
更进一步:
>>> s = '中文'
>>> s.decode('gb2312')
u'\u4e2d\u6587'
>>> len(s)
4
>>> len(s.decode('gb2312'))
2
>>> s = u'中文'
>>> len(s)
4
>>> s = '中文test'
>>> len(s)
8
>>> len(s.decode('gb2312'))
6
>>> s = '中文test,'
>>> len(s)
10
>>> len(s.decode('gb2312'))
7
能够看出,对于实际Non-ASCII编码存储的字符串,python能够正确的识别出其中的中文字符以及中文上下文中的标点符号。
前缀“u”表示“后面这个字符串“是一个Unicode字符串”,这仅仅是一个声明,并不表示这个字符串就真的是Unicode了;就比如某正太声称本身已满18岁,但实际上他的真实年龄并不肯定,如今体育界年龄造假可不稀罕幺!
那么声明成u有什么做用呢?对于Python来讲,只要你声明某字符串是Unicode,它就会用Unicode的一套机制对它进行处理。比方说,作字符串操做的时候会动用到内部的Unicode处理函数,保存的时候以Unicode字符(双字节)进行保存。等等。显而易见,对于一个实际上并非Unicode的字符串,作Unicode动做的处理,是有可能会出问题的。 u前缀只适用于你的字符串常量真的是Unicode的状况 。git
用python处理字符串很容易,可是在处理中文的时候须要注意一些问题。好比:
a = "咱们是python爱好者"
print a[0]
只能输出“我”字的前半部分,要想输出整个的“我”字还须要:
b = a[0:2]
print b
才行,很不方便,而且当一段文本中同时有中英文如何处理?最好的办法就是转换为unicode。像这样:
c = unicode(a, "gb2312")
print c[0]
这个时候c的下标对应的就是每个字符,再也不是字节,而且经过len(c)就能够得到字符数!还能够很方便的转换为其余编码,好比转换为utf-8:github
d = c.encode("utf-8") segmentfault
<type ‘str’>将字符串看做是字节的序列,而<type ‘unicode’>则将其看做是字符的序列,单个字符可能占用多个字节;字节相对于字符,其在存储层次中更低一些。数组
str转换为unicode要decode,能够这样想,由于要把字节序列解释成字符序列,字节序列是底层的存放方式,解码(decode)成更高层的字符以便使用;同理,unicode转换为str要encode,就象信息编码(encode)后才存储同样:
s.decode(encoding) <type 'str'> to <type 'unicode'>
u.encode(encoding) <type 'unicode'> to <type 'str'>
例如:
>>> s = 'str'
>>> type(s)
<type 'str'>
>>> type(s.decode())
<type 'unicode'>
>>> s = u'str'
>>> type(s)
<type 'unicode'>
>>> type(s.encode())
<type 'str'>
处理中文数据时最好采用以下方式:
1. Decode early(尽早decode, 将文件中的内容转化成unicode再进行下一步处理)
2. Unicode everywhere (程序内部处理都用unicode)
3. Encode late (最后encode回所需的encoding, 例如把最终结果写进结果文件)
下面是一个简单的演示,用re库查询一个中文字符串并打印:
>>> p = re.compile(unicode("测试(.*)", "gb2312"))
>>> s = unicode("测试一二三", "gb2312")
>>> for i in p.findall(s):
print i.encode("gb2312")编辑器
一二三函数
解决这一类的问题最好的方法就是在程序开头加上如下几行代码:测试
#coding:utf-8 import sys reload(sys) sys.setdefaultencoding("utf-8")
那么就可助你解决几乎95%的这种问题, 可是若是想刨根问底的话, 就须要去了解不少东西了.
首先, 这个就是Python语言自己的问题. 由于在Python 2.x的语法中, 默认的str并非真正意义上咱们理解的字符串, 而是一个byte数组, 或者能够理解成一个纯ascii码字符组成的字符串, 与Python 3中的bytes类型的变量对应; 而真正意义上通用的字符串则是unicode类型的变量, 它则与Python 3中的str变量对应. 原本应该用做byte数组的类型, 却被用来作字符串用, 这种看似奇葩的设定是Python 2一直被人诟病的东西, 不过也没有办法, 为了与以前的程序保持兼容.
在Python 2中做为两种字符串类型, str与unicode之间就须要各类转换的方式. 首先是一种显式转换的方式, 就是encode和decode两种方法. 在这里这两货的意思很容易被搞反, 科学的调用方式是:
str --- decode方法 ---> unicode
unicode --- encode方法 ---> str
好比:
>>> type('x') <type 'str'> >>> type('x'.decode('utf-8')) <type 'unicode'> >>> type(u'x'.encode('utf-8')) <type 'str'>
这个逻辑是这样的, 对于unicode字符串使用utf-8编码进行编码, 即调用encode('utf-8')方法生成byte数组类型的结果. 相反对于byte数组进行解码, 生成unicode字符串. 这个新手表示理解不能, 不过熟悉了就见怪不怪了.
另外是隐式的转换, 和C语言中的int转double相似, 当一个unicode字符串和一个str字符串进行链接的时候会默认自动将str字符串转换成unicode类型而后再链接. 而这个时候使用的编码方式则是系统所默认的编码方式. 使用:
import sys
print sys.getdefaultencoding()
能够获得当前默认的编码方式, 是否是'ascii'? 是的话就恭喜你中彩了~!! 在这个时候若是有如下一行代码就保证会出错:
>>> x = u'喵' >>> x u'\u55b5' >>> y = x.encode('utf-8') >>> x + y Traceback (most recent call last): File "", line 1, in UnicodeDecodeError: 'ascii' codec can't decode byte 0xe5 in position 0: ordinal not in range(128)
x是unicode类型的变量, y是x通过encode后的结果是str类型的变量. x + y的时候, 首先要将y转换成unicode字符串, 那么使用什么编码格式转换呢, 用utf-8仍是gb2312或者仍是utf-16? 这个时候就要根据sys.getdefaultencoding()来肯定, 而sys.getdefaultencoding()是'ascii'编码, 在ascii字符表中不存在0xe5这种大于128的字符存在, 因此固然报错啦! 经过加入
#coding:utf-8 import sys reload(sys) sys.setdefaultencoding("utf-8")
则能够将默认的编码转换格式变成utf-8, 且大多数状况下, 程序中的字符串是经过utf-8来编码的, 因此只要加上以上三行就能够了.
可是有没有以为, 加上这些会使得代码有些dirty? 咳, 至少对于我来讲确实很dirty. 因此我以为平时写程序的过程当中要养成尽可能使用显示的转换的习惯, 而且要明确某个函数返回的究竟是str仍是unicode, 凡是str的主动decode成unicode, 不要将二者混淆掉, 这样写出来的代码才比较干净. 此外还能够在代码最上方加入'from future import unicode_literals'能够默认将用户自定义字符串变成unicode类型.
最后我想大吼一声Python 2.x中str不是字符串, 而是B♂Y♂T♂E♂数♂组~!!
若是一个project必须在两个平台上开发,程序应该使用一样的encoding,好比要求全部的文件都使用UTF-8,若是实在不能统一(通常是为了知足许多所谓专家学者莫名其妙的要求),能够退而求其次,用当前系统编码决定文件内的编码:
import locale
import string
import re
#根据当前系统的encoding构造须要的编码取值
lang = string.upper(locale.setlocale(locale.LC_ALL, ""))
textencoding = None 3
#检查编码的值是否是知足咱们须要的状况
if re.match("UTF-8", lang) != None:
# UTF-8编码
textencoding = "utf-8"
elif re.match(r"CHINESE|CP936", lang):
# Windows下的GB编码
textencoding = "gb18030"
elif re.match(r"GB2312|GBK|GB18030", lang):
# Linux下的GB编码
textencoding = "gb18030"
else:
# 其余状况,抛个错误吧
raise UnicodeError
fd = file(filename, "r")
fulltextlist = fd.readlines()
# 把每一行转换成unicode
for each in len(fulltextlist):
fulltextlist[i] = unicode(each, textencoding)
fd.close()
# 若是要打印的话,能够用text.encode(encoding)来恢复成多字节编码
编码encoding发生在Unicode字符串转换为字节序列时,而解码decoding发生在字节序列转换为Unicode字符串时(encoding always takes a Unicode string and returns a bytes sequence, and decoding always takes a bytes sequence and returns a Unicode string)。
UnicodeDecodeError
UnicodeDncodeError一般发生在将str字符串解码为特定Unicode字符串时。因为不一样的编码只能映射部分str字符串到对应的Unicode字符,因此遇到一些字符时解码会失败。
UnicodeEncodeError
UnicodeEncodeError一般发生在将Unicode字符串编码为特定字节序列时。因为不一样的编码只能映射部分Unicode字符到对应的str字符串,因此遇到一些字符时编码会失败。
处理python编码转换时的UnicodeDecodeError异常
python提供的unicode转换不像iconv或是mbstowcs之类的方便。若是转换一段unicode("1234中文",'ascii') 到utf8,会直接出现UnicodeDecodeError的错误。若是在你能预知字串符的编码的时候,好比你用unicode('1234中文', 'gbk') 就不会出现错误;不过不少时候,会出现CJK混合的状况,若是要作到将一段CJK文件转换成unicode可能就行不通了。好在python的codecs提供了register_error这个功能:
register_error(name, error_handler)
原理很简单,不过要先看unicode是如何处理异常的。unicode这个函数是将一段string按输入的编码转换成目标的编码,若是出现了不与输入编码相符的,会出现一个UnicodeDecodeError的异常,一般有三种处理方法:strict、replace、ignore;默认是 strict,就是直接raise UnicodeDecodeError。经过register_error,咱们也能够有本身的处理方法,若是遇到与输入的编码不符的时候,咱们就本身识别,好比GBK、BIG五、JP的字符。
def cjk_replace(exc):
if not isinstance(exc, UnicodeDecodeError):
raise TypeError("don't know how to handle %r" % exc)
if exc.end + 1 > len(exc.object):
raise TypeError('unknown codec ,the object too short!')
ch1 = ord(exc.object[exc.start:exc.end])
newpos = exc.end + 1
ch2 = ord(exc.object[exc.start + 1:newpos])
sk = exc.object[exc.start:newpos]
if 0x81<=ch1<=0xFE and (0x40<=ch2<=0x7E or 0x7E<=ch2<=0xFE): # GBK
return (unicode(sk,'cp936'), newpos)
if 0x81<=ch1<=0xFE and (0x40<=ch2<=0x7E or 0xA1<=ch2<=0xFE): # BIG5
return (unicode(sk,'big5'), newpos)
raise TypeError('unknown codec !')
codecs.register_error("cjk_replace", cjk_replace)
咱们的cjk_replace如今只能处理GBK与BIG5的,由于我对编码也不是特别了解,只是大概知道GBK与BIG5的,不太了解JP的。在 cjk_replace这个函数里,咱们对不认识的文字进行手工识别,若是认识的编码,就用正确的方法,并返回编码后的内容与新的pos,好比“1234中文”,在pos为4的时候,会调用咱们的cjk_replace,咱们会返回一个从gbk转换成utf8的“中”字,并返回下个正确的位置“文”的起始位置。固然了,处理“文”的时候,还会再调用一次。下面看看是如何使用的:
filedata = open('test.txt','r).read() #gbk and big5 file
data = unicode(filedata,'ascii','cjk_replace').encode('utf8')
小结
一个比较通常的Python中文处理的流程:
* 将欲处理的字符串用unicode函数以正确的编码转换为Unicode
* 在程序中统一用Unicode字符串进行操做
* 输出时,使用encode方法,将Unicode再转换为所需的编码
有几点要说明一下:
* 所谓“正确的”编码,指得是指定编码和字符串自己的编码必须一致。这个其实并不那么容易判断,通常来讲,咱们直接输入的简体中文字符,有两种可能的编码:GB2312(GBK、GB18030)、以及UTF-8
* encode成本地编码的时候,必需要保证目标编码中存在欲转换字符的内码。encode这种操做通常是经过一个本地编码对应Unicode的编码转换表来进行的,事实上每一个本地编码只能映射到Unicode的一部分。可是映射的区域是不一样的,好比Big-5对应的Unicode的编码范围和 GBK对应的就不同(实际上这两个编码有部分范围是重叠的)。因此,Unicode的一些字符(好比自己就是从GB2312转换来的那些),能够映射到 GBK,但未必能够映射到Big-5,若是你想转换到Big-5,颇有可能就会出现编码找不到的异常。但UTF-8的码表范围实际上和Unicode是同样的(只是编码形式不一样而已),因此,理论上来讲,任何本地编码的字符,均可以被转换到UTF-8
* GB23十二、GBK、GB18030本质上是同一种编码标准。只是在前者的基础上扩充了字符数量
* UTF-8和GB编码不兼容
* 出现编解码异常时可能须要本身编写编解码解析函数,这须要了解一些字符编码的知识
一、写的代码模块须要指定编码
若是代码没有指定coding,python就默认全部的字符为ASCII码,
ASCII码只支持256个字符,ASCII码不支持中文,因此就报错。
因此要在代码前写上#coding:utf-8或#coding:gbk
建议你的代码统一写成这样:
#coding:utf-8 import sys reload(sys) sys.setdefaultencoding('utf-8')
二、python2内部全部编码统一为unicode
unicode能够处理世界上全部语言的字符。
utf-8为unicode的一种实现形式,因此须要在代码前写上#coding:utf-8
三、编码转换
牢记python2内部编码为unicode.
其它的编码decode()为unicode,再编码encode()为你指定的编码,就不会出现乱码。
四、网页采集时
代码指定#coding:utf-8
若是网页的编码为gbk
须要这样处理:
html = html.decode('gbk').encode('utf-8')
五、代码前也能够写#coding:gbk,但也要保证你的代码文件的保存格式为gbk.这个在windos下会出现这样的问题。
六、字典等key或值的汉字问题
#coding:utf-8
dict1 ={1:'python周末培训班',2:'咨询010-68165761 QQ:1465376564'}
print dict1
# 这样输出的没有显示汉字,是显示汉字的其它编码
dict2 ={1:'python视频培训班',2:'咨询010-68165761 QQ:1465376564'}
for key in dict2:
print dict2[key]
七、unicode的汉字编码写到文本文件中
须要根据文本文件的编码进行转换
能够encode('utf-8')或encode('gbk')
总结:凡是报错信息中出现的错误包含“ASCII”,就是没有指定汉字编码的问题。
一、 http://bbs3.chinaunix.net/thread-1389703-1-2.html
二、 Python的中文处理及其它
http://www.go4pro.org/?p=38
三、 Python处理中文的时候的一些小技巧
http://cocre.com/?p=461
四、 Unicode In Python, Completely Demystified. Kumar McMillan
http://farmdev.com/talks/unicode
五、 python中文处理好方法
http://www.okpython.com/bbs/viewthread.php?tid=311
六、 Python的中文处理
http://hi.baidu.com/mrsz/blog/item/7812a5018c2cf2031d9583d2.html
七、 UnicodeDecodeError
http://wiki.python.org/moin/UnicodeDecodeError
八、 UnicodeEncodeError
http://wiki.python.org/moin/UnicodeEncodeError
九、 如何处理python编码转换时的UnicodeDecodeError异常
http://blog.chinaunix.net/u/8873/showart_1009737.html
十、codecs — Codec registry and base classes
http://docs.python.org/library/codecs.html
十一、python 中文乱码 问题深刻分析
http://blog.csdn.net/kiki113/article/details/4062063
十二、python新手必碰到的问题---encode与decode,中文乱码[转]
http://www.51testing.com/?uid-524463-action-viewspace-itemid-817888
1三、Python 编码和 Unicode(深刻理解 python 编码的文章,推荐阅读)
http://blog.jobbole.com/50345/
1四、关于python2中的一个编码问题(u'\xe5\xb0\x8f\xe4\xb8\x89' 与 '\xe5\xb0\x8f\xe4\xb8\x89' 的区别)
http://segmentfault.com/q/1010000000370030
1五、Python的中文编码问题
http://python.jobbole.com/80831/
1六、在Python中正确使用Unicode
http://python.jobbole.com/80939/
1七、Python字符编码详解
http://python.jobbole.com/82107/
1八、一个例子搞懂编码问题(深刻浅出 python 编码的文章,推荐阅读)
http://bindog.github.io/blog/2014/12/16/python-coding/
1九、Python 编码的前世此生