python学习:编码中遇到的问题原因及解决方案

最近学python,2跟3版本的都有用到,两者在编码上还有点区别,特地查了点资料,自己归纳整理一下。可能会有点小错误,欢迎大家一起讨论~


一、首先明确一下几大编码格式:

ASCII        #1个字符占用1个字节

GBK         #专门用来编码汉字,是GB2312的扩展,增加了繁体字、日文的假名等

Unicode   #2个字节

utf-8         #英文1个,中文3个字节(它是unicode的实现方式之一)


最早的编码是ASCII,美国人发明的,包含大小写英文字母、数字0-9(这里的0-9是字符,即‘0’与0不同)和一些特殊符号共127个符号,占用空间1个字节(8位二进制)。因为ASCII码不包含中文,所以诞生了GB2312,专门用来编码中文,后来完善为GBK。当然,基本每个国家都会针对自己的语言开发一套编码,所以为了将各个国家的编码统一起来,不致于交互时出现乱码,Unicode诞生了(内部统一了ASCII和GBK等编码)。Unicode编码了几乎所有的字符,但他只是代表了编码标准(具体的实现形式仍是GBK、ASCII等)。unicode一个字符大概占用2个字节(生僻的需要3、个/4节),这在英文字母较多的情况下会占用过多的空间,这是不能容忍的,所以又诞生了utf-8,utf-8将英文字母还按一个字节编码,将中文编码成3个字节,节省了空间。基本可以说utf-8是Unicode的存储实现方式。


以上我们可以看出,

①ASCII、GB2312、GBK、unicode是向下兼容的,后面的编码内部都含有前面的编码,所以用后面的编码对前面的进行解码不会出现乱码。

②而utf-8编码的文件使用GBK解码时,如果不声明则会出现乱码的情况。


二、python2和系统内部编码

明确以下几点:

1、区分decode(解码)和encode(编码)

简单来说,就是一个字符,要保存的时候,就用encode按照选择的编码规则保存,要读取的时候,就用decode按照选择的编码规则来解码读取。

如果现在一个字符a是GBK格式,那要读取他就需要使用a.decode('gbk')来解码。

要将一个GBK格式保存的字符转换成utf-8保存,就需要先解码再编码,即a.decode('gbk').encode('utf-8')。知道了这些后再来看看以下几点:

①计算机内存统一采用Unicode编码。当需要保存到硬盘或传输(如网页内容)的时候,就转成utf-8(这就是上文说到的utf-8是Unicode的存储实现形式的原因,当读取到内存的时候,编码为Unicode,需要保存时则采用utf-8)

②windows系统下cmd执行时,采用的是gbk解码。

③写代码的记事本如sublime、notepad本身保存代码是有个默认编码格式的,一般为utf-8。

④python2的交互操作界面默认对中文采用gbk编码和解码。

⑤python的默认解码方式(decode)是ascii,因为ASCII编码中不存在中文,所以内部含有中文的时候会抛出异常;默认编码方式(encode)是unicode


知道了上述的编码和解码规则之后我们就能解决大部分的python2乱码问题了。


2、编码规则声明和实际问题解决

大部分人编写代码通常是采用的sublime或notpad等记事本编辑代码脚本,然后保存,(只要保存就肯定要以某种编码形式存储代码),然后在cmd或者交互界面下执行(这时有解码)。

而python在读取源代码文件时,不声明情况下,默认是用ASCII解码,所以存在中文时就容易抛出异常。所以通常我们会在文本文件的开头加上#-*- coding utf-8 -*-  ,表示文本内部采用utf-8的编码规则,python解码的时候则也使用utf-8解码。但是仍然会遇到问题如:

脚本文件:

# -*- coding:utf-8 -*-
a='你好'
print a
print repr(a)   #打印a的编码值

cmd下结果:


可以看出用utf-8编码的文本在cmd命令行下运行得到的是乱码,这就是咱们前面提到的cmd下是使用的gbk规则,要解决这种冲突主要有以下几种办法:

①将文本的保存格式改为gbk,同时将声明改为gbk如 #-*- coding:gbk -*-                

                                                                                  #不推荐,因为utf-8的应用较广泛,通常还特地将文本保存成utf-8 

②将语句改为print a.decode('utf-8').encode('gbk')    #较麻烦 

③将中文字符声明为unicode格式,a=u'啊哈'            #最常用的做法


结果(编码已被改为gbk):


此外,python默认会对字符先采用decode,再encode,未声明时则使用默认的de和en格式,如下:

<span style="font-size:14px;">#-*- coding:utf-8 -*-
s = "你好"
s.encode('gbk')    #默认先用ascii来decode
s.decode('utf-8')   #默认最后用unicode来encode</span>

以上语句在真正执行的时候s.encode('gbk')会报错,因为其默认decode方式为ascii,对中文不支持。这也是经常导致编码出错的原因之一。



三、python常见的其他编码问题

看了上文的介绍,基本可以知道出现乱码的情况就是编码规则的不同导致的。

接下来说说我这几天遇到的编码问题:

①在python2里,通常只要声明unicode之后都能正常打印,但是有个例外就是input函数,input函数夸号里要是加入了中文字符的话必须使用上面提到的第二种方法进行操作否则会抛出乱码:

a=input('请输入数字:'.decode('utf-8').encode('gbk'))   #不添加后面的decode,encode,字符串‘请输入数字’将在屏幕上显示为乱码
②通常我们从网页上获取数据或爬取数据的时候,网页的编码格式都是采用的utf-8,所以爬取下来的数据通常要采用utf-8解码,转成字符串str,否则经常会在后续出现乱码的情况:

content=response.read().decode('utf-8')


四、了解python中的str字符串对象和编码区别

查了点资料,自己归纳理解了一下。我觉得首先str应该算是一种在执行中生成的字节流,他本身不具有固定的编码格式,他的具体编码格式由声明来确定,如下:

#-*- coding:utf-8 -*-
a='你好'

如果以上语句被保存为一个脚本文件,那么这个时候a便是采用的utf-8来编码。

如果在python交互界面中输入a='你好',则a默认采用交互界面的默认编码格式。

综上所述,str是一种字节流,没有其他含义,而编码则是一种对文本包括字符串的编码格式。我们可以把具有unicode编码格式的字符串看做字节流,但是不能随意把他当做unicode字符串来看。



五、python2跟3的区别

python2里把编码分为unicode和非unicode,python3则统一采用unicode保存,所以3对中文的支持特别好,很多时候不用刻意进行转码,如上面的input问题在3中就几乎不用进行转码


以上。

刚开始接触编码,要是有哪里写的不对的,大家多给我提提哈,互相学习~大笑



参考资料:

http://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/001431664106267f12e9bef7ee14cf6a8776a479bdec9b9000

http://www.cnblogs.com/ymy124/archive/2012/06/23/2559282.html

http://www.server110.com/python/201402/6393.html

http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html








發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章