1. python2的默认编码是ascii,python3的默认编码是utf-8python
Python 2.7.12 (v2.7.12:d33e0cf91556, Jun 27 2016, 15:24:40) [MSC v.1500 64 bit (AMD64)] on win32 Type "help", "copyright", "credits" or "license" for more information. >>> import sys >>> sys.getdefaultencoding() 'ascii' Python 3.6.2 (v3.6.2:5fd33b5, Jul 8 2017, 04:57:36) [MSC v.1900 64 bit (AMD64)] on win32 Type "help", "copyright", "credits" or "license" for more information. >>> import sys >>> sys.getdefaultencoding() 'utf-8'
2. 常见编码状况linux
print sys.getdefaultencoding() #系统默认编码 print sys.getfilesystemencoding() #文件系统编码 print locale.getdefaultlocale() #系统当前编码 print sys.stdin.encoding #终端输入编码 print sys.stdout.encoding #终端输出编码
window终端输出windows
ascii mbcs ('zh_CN', 'cp936') cp936 cp93
linux终端输出bash
ascii UTF-8 ('zh_CN', 'UTF-8') UTF-8 UTF-8
3. python str->unicode是decode,unicode->str是encode,见下图函数
>>> import sys >>> sys.getdefaultencoding() 'ascii' >>> a='强' # str字符串 >>> b=u'强' # unicode字符串 >>> print isinstance(a, str) True >>> print isinstance(b, unicode) True # 由于只有unicode才有encode方法,此处python会作默认转换,也即a.decode('ascii').encode('utf-8') # 会获取默认编码ascii转换中文字符,固然错误,报UnicodeDecodeError >>> a.encode('utf-8') Traceback (most recent call last): File "<stdin>", line 1, in <module> UnicodeDecodeError: 'ascii' codec can't decode byte 0xc7 in position 0: ordinal not in range(128) # 指定utf-8再转换就会正确解析,结果unicode字符串,注意u'\u01ff'前面的u,观察这个便可知道当前是unicode or 二进制字节码 >>> a.decode('utf-8') u'\u01ff' # 不需转换,显示二进制字节码 >>> str(a) '\xc7\xbf' # b是unicode类型,需转化为str类型,b.encode('ascii')报错 >>> str(b) Traceback (most recent call last): File "<stdin>", line 1, in <module> UnicodeEncodeError: 'ascii' codec can't encode character u'\u5f3a' in position 0: ordinal not in range(128) # unicode没有decode,需转为str,b.encode('ascii'),转化时出错 >>> b.decode('utf-8') Traceback (most recent call last): File "<stdin>", line 1, in <module> File "C:\Python27\lib\encodings\utf_8.py", line 16, in decode return codecs.utf_8_decode(input, errors, True) UnicodeEncodeError: 'ascii' codec can't encode character u'\u5f3a' in position 0: ordinal not in range(128) # 指定编码正确转换 >>> b.encode('utf-8') '\xe5\xbc\xba' >>>
4. python进行同时包含str和unicode的运算时(+,%等),一概转为unicode处理,固然结果也是unicodeui
>>> a='强' # str字符串 >>> b=u'强' # unicode字符串 # 这里str和unicode运算,所有转化为unicode,str转unicode时用ascii转换,固然报错 >>> a+b Traceback (most recent call last): File "<stdin>", line 1, in <module> UnicodeDecodeError: 'ascii' codec can't decode byte 0xc7 in position 0: ordinal not in range(128) # 此处都是str不用转,正确 >>> '强%s' % a '\xc7\xbf\xc7\xbf' # 此处b是unicode,至关于'强%s'.decode('ascii') % b, 因此错误 >>> '强%s' % b Traceback (most recent call last): File "<stdin>", line 1, in <module> UnicodeDecodeError: 'ascii' codec can't decode byte 0xc7 in position 0: ordinal not in range(128) # 反过来也是同样的 >>> u'强%s' % a Traceback (most recent call last): File "<stdin>", line 1, in <module> UnicodeDecodeError: 'ascii' codec can't decode byte 0xc7 in position 0: ordinal not in range(128) >>> u'强%s' % b u'\u5f3a\u5f3a'
5. 以上都是默认ascii编码致使的,那么设置下python默认编码就能够了编码
>>> import sys >>> sys.setdefaultencoding('utf-8') Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'module' object has no attribute 'setdefaultencoding' # 注意须要reload下 >>> reload(sys) <module 'sys' (built-in)> >>> sys.setdefaultencoding('utf-8') >>> sys.getdefaultencoding() 'utf-8' >>> a='强' # str字符串 >>> b=u'强' # unicode字符串 # 再进行以上操做,都正确了 >>> a+b u'\u01ff\u5f3a' >>> '强%s' % a '\xc7\xbf\xc7\xbf' >>> '强%s' % b u'\u01ff\u5f3a' >>> u'强%s' % a u'\u5f3a\u01ff' >>> u'强%s' % b u'\u5f3a\u5f3a' >>> a.encode('utf-8') '\xc7\xbf' >>> b.decode('utf-8') u'\u5f3a' >>> str(a) '\xc7\xbf' >>> str(b) '\xe5\xbc\xba'
6. python文件默认编码也是ascii,假若有中文就会报错以下code
假若有t.py文件,里面有非ascii字符orm
# file t.py a='夏天'
执行时会报错utf-8
E:/>python t.py File "t.py", line 1 SyntaxError: Non-ASCII character '\xcf' in file t.py on line 1, but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details
在头部加入,指定源代码编码格式
# -*- coding: utf-8 -*- 或者 #coding=utf-8
声明下默认编码便可
7. 如文件编码为ANSI的,里面有中文的unicode定义,也会报错
t.py
#coding=utf-8 a='夏天' b=u'秋天'
执行也会报错
E:\>python t.py File "t.py", line 3 b=u'秋天' SyntaxError: (unicode error) 'utf8' codec can't decode byte 0xc7 in position 0: invalid continuation byte
把文件编码改成UTF-8便可解决
8. print, 终端乱码
print和终端相关,会根据sys.stdin.encoding, sys.stdout.encoding来处理,若是输出的字符串和终端编码不同就会乱码
t.py
#! -*- coding:utf-8 -*- a='中文' print a print type(a)
windows下
E:\>python t.py 涓枃 <type 'str'>
linux下
# python t.py 中文 <type 'str'>
由于windos控制台编码为cp936编码即gbk编码,而变量a自己编码为utf-8
那么定义的unicode字符如何呢,见下面
#! -*- coding:utf-8 -*- a='中文' print a # 涓枃 print type(a) # <type 'str'> b=a.decode('utf-8') print b # 中文 b=u'中文' print b # 中文 print type(b) # <type 'unicode'> print b.encode('gbk') # 中文 str(b) # UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)
可见,unicode的字符print正常,按gbk encode->str时也正常,为何呢
可这样简单理解,print输出到终端时,要是str,若是str的编码与终端编码不一致,那么乱码
若是不是str,则须要转为str,这个是获取终端编码,也即python替你作了, encode('gbk')
但str(b)咋又报错了呢,这是由于,str是python内建函数,会获取getdefaultencoding,而这个编码是ascii,因此报错
再进一步,加入重定向到文件呢
#! -*- coding:utf-8 -*- b=u'中文' print b
python t.py > result
会报错UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)
由于输出到控制台时,print 使用的是控制台的默认编码,而重定向到文件时,print 就不知道使用什么编码了,因而就使用了默认编码 ascii 致使出现编码错误。这时咱们就不该该让python帮咱们作,咱们本身指定
#! -*- coding:utf-8 -*- b=u'中文' print b.encode('utf-8')
这样就会正常
9. write
#! -*- coding:utf-8 -*- with open('ttt.txt', 'w') as f: f.write('test') # 正常写入 f.write('夏天') # 正常写入 #f.write(u'秋天') # 错误,因为是unicode,python要转换为str再写入,encode时用的ascii,触发UnicodeEncodeError异常 f.write(u'秋天'.encode('utf-8')) # 写入正常,unicode->str
或者指定默认编码,这样就不用手动encode了,见下
#! -*- coding:utf-8 -*- import sys reload(sys) sys.setdefaultencoding('utf-8') with open('ttt.txt', 'w') as f: f.write('test,') # 正常写入 f.write('夏天,') # 正常写入 f.write(u'秋天,') # 写入正常
10. read
#! -*- coding:utf-8 -*- import sys reload(sys) sys.setdefaultencoding('utf-8') with open('ttt.txt', 'w') as f: f.write('test,') # 正常写入 f.write('夏天,') # 正常写入,乱码 f.write(u'秋天,') # 写入错误,因为是unicode,python要转换为str再写入,encode时用的ascii,触发UnicodeEncodeError异常 #f.write(u'秋天'.encode('utf-8')) # 写入正常,unicode->str with open('ttt.txt') as f: for line in f: print line, type(line) # test澶忓ぉ绉嬪ぉ <type 'str'> line2 = line.decode('utf-8') print line2, type(line2) # test夏天秋天 <type 'str'> print '-----------------------------' # 经过io包下的open打开文件可设置编码 from io import open with open('ttt.txt', encoding='utf-8') as f: for line in f: print line, type(line) # test夏天秋天 <type 'unicode'> # 由上可见,内建函数open,不能指定编码,其按客户端所在编码解码,line类型是str # io.open可指定编码,同时line读取类型为unicode
建议措施:
以上全部其实就是在不一样地方python默认转换时采用的编码和咱们设置的编码不一致致使的,因此分析时先分析当前python应该获取什么编码,而后再分析。好比,str(..) 会获取getdefaultencoding,print会获取sys.stdout.encoding等
1. 牵扯到中文的地方,都声明头部编码,同时文件编码设为utf-8
# -*- coding: utf-8 -*- 或者 #coding=utf-8
2. 同时设置sys 默认编码
import sys reload(sys) sys.setdefaultencoding('utf-8')
3. python代码内部请所有使用unicode编码,在获取外部内容时,先decode为unicode,向外输出时再encode为str
4. 在定义变量或者正则时,也定义unicode字符,如a=u”中文”;res=r””+u”正则”。