最近的工作经常遇到一些中文编码问题,搞得头疼,做个总结。
1. python2 和 python3 的 open 的区别
python2的open比python3少一个encoding参数,不能指定编码类型,如下:
python2:
f = open('test.txt', 'a')
python3:
f = open('test.txt', 'a', encoding = 'utf-8')
解决这个问题可以用codecs模块的open,如下:
import codecs
f = codecs.open('test.txt', 'a', encoding = 'utf-8')
如果在写程序头部加上了# coding: utf-8
那么生成的txt文件就会是utf-8编码格式的。但是实际应用中,因为utf-8的中文涵盖不够广,有时候我们
# coding: gbk
甚至# coding: gb2312
,在这种情况下生成的txt文件就会变成ANSI编码格式的,这种情况下很多很多中文都会乱码,这种时候如果使用python2要生成utf-8编码格式的txt文件,就要采用codecs.open
。
2. unicode, decode, encode
字符串在Python内部的表示是unicode编码,因此,在做编码转换时,通常需要以unicode作为中间编码,即先将其他编码的字符串解码(decode)成unicode,再从unicode编码(encode)成另一种编码。
decode的作用是将其他编码的字符串转换成unicode编码,如str1.decode('gb2312')
,表示将gb2312编码的字符串str1转换成unicode编码。
encode的作用是将unicode编码转换成其他编码的字符串,如str2.encode('gb2312')
,表示将unicode编码的字符串str2转换成gb2312编码。
因此,转码的时候一定要先搞明白,字符串str是什么编码,然后decode成unicode,然后再encode成其他编码。
注意:windows控制台的默认编码是gbk。
如果要将控制台编码修改成utf-8,可以在cmd用命令:
CHCP 65001
65001就是utf-8的编码代号,具体可以再参照网上的资料。
3. sys.setdefaultencoding()
参考:https://blog.csdn.net/crazyhacking/article/details/39375535
在python2里,有时候乱码就必须要加这一句:
import sys
reload(sys)
sys.setdefaultencoding('gbk')
Python 里面的编码和解码也就是 unicode 和 str 这两种形式的相互转化。编码是 unicode -> str,相反的,解码就是 str -> unicode。剩下的问题就是确定何时需要进行编码或者解码了。关于文件开头的"编码指示",也就是# -*- coding: -*-
这个语句。Python 默认脚本文件都是 UTF-8 编码的,当文件中有非 UTF-8 编码范围内的字符的时候就要使用"编码指示"来修正。关于 sys.defaultencoding,这个在解码没有明确指明解码方式的时候使用。
但是这种做法并不是完美的。
参考:https://blog.ernest.me/post/python-setdefaultencoding-unicode-bytes
会造成编码错误和dictionary行为异常。
原因:python混淆 byte string 和 text string。
在Python2里,有三大类 string 类型,unicode(text string),str(byte string,二进制数据),basestring是前两者的父类。
在Python3中,终于就修改了:就像前文提到了,Python3的默认编码是 Unicode,这也就意味着,做所有需要转换的场合,都能正确并成功的转换。
如果实在要使用Python2,那么最好遵循以下三个原则,不容易出错。
- 所有 text string 都应该是unicode类型,而不是 str,如果你在操作 text,而类型却是 str,那就是在制造 bug。
- 在需要转换的时候,显式转换。从字节解码成文本,用
var.decode(encoding)
,从文本编码成字节,用var.encode(encoding)
。 - 从外部读取数据时,默认它是字节,然后 decode 成需要的文本;同样的,当需要向外部发送文本时,encode 成字节再发送。