python中文乱码问题详解

序:

总是有人问”python乱码”问题,在这里,我做一下解答,希望以后有遇到类似问题的人,能自行解决。

引子:

 

最近在学习写smtp+pop3客户端,由于发/收的邮件中的中文都是乱码,于是百度,看到上面这个截图,多次尝试,乱码问题解决,后面讲我的解决过程。

 

原理:

乱码根本原因在于“编码-解码不一致”

python中,我们使用decode()和encode()来进行解码和编码, 在python中,使用unicode类型作为编码的基础类型。即

显示数据两个来源:源代码引用的外部数据(socket,file,raw_input)、源代码内部的数据

数据源编码:是指源代码引用外部数据,外部数据编码需要与显示程序编码一致,例如源代码使用socket对网页抓包,网页数据即为数据源,而网页本身是有特定编码的。

源代码编码:python源代码默认使用ASCII编码,当部分字符无法ASCII编码时,默认使用用户申明的编码例如# encoding: utf-8,如果不申明,可能会因编辑器的不同,打开源代码出现乱码情况。源代码编码需要与显示程序编码一致。

 

显示编码:黑白显示器只能显示黑白,如果输入彩色信号也是如此,显示输出的程序对编码同样有要求,要显示的数据需要与显示程序要求的编码一致。

常见显示编码:在windows中,如果双击python***.py文件,则默认调用python shell解释,并使用windows cmd shell(cp936编码)程序做输出,在linux终端SecureCRT显示数据通常设置使用utf-8编码,python自带的IDLE在windows下默认使用cp936编码。

编码:通过上面描述我们知道【显示数据编码需要与显示数据程序编码一致】,那么如何一致呢?需要通过中间编码unicode实现一致源编码—>unicodeà—>目标编码

例如网页常使用gb2312编码(数据源utf-8编码暂不考虑),*.py源代码通常使用utf-8编码,显示端初学者学用windows cmd 的cp936编码,要保持一致可如此修改print‘string’语句:  (string来自网页)             print‘string’.decode(‘GB2312’).encode(‘cp936’).

其中‘string’.decode(‘GB2312’)à变为unicode,而*.encode(‘cp936’)则让unicode编码à显示端的cp936编码。

解决思路:

查看编码信息:

邮件编码

我使用poplib抓取邮件信息,了解到邮件使用GB2312编码

 

网页编码

想要对网页数据抓取的朋友,必须对网页的编码信息准确获取。对目标网站源代码做如下搜索即可发现编码方式:

 

<meta http-equiv="content-typecontent="text/html;charset=utf-8">

 

数据传输编码

 

 

正确解码:

编码与解码关系

一个比喻:编码是如何保存的问题,解码是如何显示的问题。

Window编码解码流程:

源代码解码:

ASCII/utf-8 ->unicodestr. decode('utf-8'))->cp936(str. encode('cp936'))

数据类型:ASCII/utf-8(<type ‘str’>) ;unicode(<type ‘unicode’>) ;cp936(<type ‘str’>)

cp936为unicode是中文子集,因此unicode已经可以在windows下正确显示。

源代码引用外部数据解码:

假设外部数据使用xx编码:xx àunicodeàcp936

 

python中的编码与解码

Python 源代码默认编码为ASCII码,在源代码申明utf-8后,发生了编码过程非ASCII字符àutf-8.  

先说一下python中的字符串类型,在python中有两种字符串类型,分别是strunicode,他们都是basestring的派生类;str类型是一个包含Characters represent (at least) 8-bit bytes的序列;unicode的每个unit是一个unicode obj;所以:

len(u'中国')的值是2;len('ab')的值也是2;

在str的文档中有这样的一句话:The string data type is also used to represent arrays of bytes, e.g., to hold data read from a file. 也就是说在读取一个文件的内容,或者从网络上读取到内容时,保持的对象为str类型;如果想把一个str转换成特定编码类型,需要把str转为Unicode,然后从unicode转为特定的编码类型如:utf-8、gb2312等;(码不一时,通常unicode作为

 

一些实例:

eg1. 源代码编码

此例中变量s,与print s的显示环境linux bash shell都使用相同的编码utf-8编码,因此没有出现乱码。

编程过程:utf-8 /ASCIIàpython shell传递给linux bash shell(使用utf-8解码)显示

  

注意unicode(变量,’utf-8) / u”string”与默认ASCII编码的区别 

 

eg2.将eg1中的代码使用windows环境运行,结果出现乱码,这是因为,变量s为ASCII编码,而windows cmd shell作为显示程序 使用cp936编码显示,当然乱码

编码过程:utf-8/ASCIIàcmd shell(cp936解码)显示

   

解决办法,让输出的ASCII/utf-8编码转码为cp936编码,乱码解决

 

eg 3.邮件编码(数据源编码)

 

翻阅历史邮件,查询编码方式

 

正确解码:GB2312à’string’.decode(‘GB2312’)àunicodeàutf-8

 

运行程序

 

 

 

技巧与方法:

sys.defaultencoding模块

 


 Python 使用sys.defaultencoding 的默认编码ASCII编码解码,但变量s的编码为utf-8编码,因此报错。

解决办法一:明确指定解码方式

 

解决办法 二:设置默认解码方式sys.setdefaultencoding('utf-8')

 

 

codecs.open()方法

用于解决文件读写时的编码问题

 

Python3的编码

在新版本的python3中,取消了unicode类型,代替它的是使用unicode字符的字符串类型(str),字符串类型(str)成为基础类型如下所示,而编码后的变为了字节类型(bytes)但是两个函数的使用方法不变:

     decode              encode

bytes ------> str(unicode)------>bytes

u = '中文' #指定字符串类型对象u,默认unicode编码

str = u.encode('gb2312'#gb2312编码对u进行编码,获得bytes类型对象str

u1 = str.decode('gb2312')#gb2312编码对字符串str进行解码,获得字符串类型对象u1

u2 = str.decode('utf-8')#如果以utf-8的编码对str进行解码得到的结果,将无法还原原来的字

 参考文章:

http://blog.csdn.net/turkeyzhou/article/details/8927361

http://www.cnblogs.com/zhaoyl/p/3770340.html

http://www.pythonclub.org/python-basic/encode-detail

http://wolfmaster.iteye.com/blog/638029

http://blog.chinaunix.net/uid-517401-id-353375.html

 


  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值