Python2 新手 编码问题 吐血总结

什么是编码

  任何一种语言、文字、符号等等,计算都是将其以一种相似字典的形式存起来的,好比最先的计算机系统将英文文字转为数字存储(ASCII码),这种文字与数字(或其余)一一对应的关系咱们称之为编码。因为ASCII码只包含了大小写英文字母、数字和一些符号,显然当计算机推广到世界以后随着语种增多,这套编码并不适用,因而中国针对中文推出了GB2312码,可是多语言时,又不行了,因而就出现了强大的Unicode(万国码)。可是因为Unicode存储性能问题,在纯英文时存储效率要远低于ACSII码,因而又出现了如今的UTF-8编码(8-bit Unicode Transformation Format),能够看作是Unicode的增强版,经过可变长度的编码来使存储最优,并且UTF-8编码包含了ASCII码,这一点很是重要。
  python处理文本时的中间编码为Unicode,因而就有了decode和encode,前者将unicode之外的字符串解码为unicode,后者将unicode编码为指定编码。python

当你输入字符串时

  首先,当你在python代码中输入一个字符串时候,它是以什么编码形式被保存的呢?linux

1.若是输入了一串纯英文,数字,或英文状态下的标点符号,那么不管有没有在代码最前面作编码申明(如"# -- coding:utf-8 --"),字符串都是由ASCII码存储的,缘由很简单,ascii码只支持英文,占用性能与空间小。git

  • 此时,该字符串能够随意decode(解码)和encode(编码),不会报错,甚至不会进行任何变更,永远都是ascii码,type类型是str
  • 若是在输入该字符串时加入了Unicode申明,即 u"balabala",那么此时字符串type格式为Unicode,能够随意encode,不可decode,可是不管encode成什么,python仍是都会以ascii的形式存储

2.若是输入了中文,那么状况一会儿就变得复杂起来。此时必须进行编码申明,不然会抛出以下错误:“Non-ASCII character '\xe5' in file **,but no encoding declared”,意思就是你输入了ASCII码没法识别的东西,且没有进行编码申明,因此此时要在文件开头进行编码申明,完整版以下:github

#!/usr/bin/python
# -*- coding: <encoding name> -*-

  此时 处填上编码方式,不区分大小写,其实只写下面一行就好了,上面一行只是为了在linux系统里识别而已。不少人对这种在注释中进行申明的方式很不习惯,也不解-*-是什么鬼,可是 PEP 263告诉咱们,这样只是为了好看而已。。。 编程

  • 举个例子,若是你申明了utf-8编码,那么你输入的任何带有非英文(以及符合)非数字的字符串,都是utf-8编码,咱们能够经过 .decode('utf-8')的方式将其解码为Unicode码方便python处理,注意此时不只其编码编程Unicode,其类型也从str变成了Unicode。固然也可使用unicode(string,'utf-8')的方式来将其解码为unicode,Unicode函数与str函数的区别是前者尝试用给定编码(不给定时用ASCII)进行decode,然后者尝试用ASCII(defaultencoding)进行encode,因为ASCII码被utf-8码包含,因此对于utf-8字符串,进行str()是没有问题的,可是对于其余编码文本进行str()则会报错或是乱码。
  • 若是输入字符串时进行Unicode申明,如a=u"杨睿很帅",那么此时字符串编码直接为unicode。可随意进行encode,不可decode,不可str。

注意

1.chardet库的detect方法能够获得字符串的编码类型,当输入字符串为unicode时程序报错,有时候也会误判,置信水平小鱼0.7则不可轻信了。c#

2.上述只针对在非DOS中执行py文件时适用:若是是在IDLE中单步执行,则中文字符串是以系统默认编码(windows-1252)保存;若是是在DOS界面中运行,则为GBK编码,并且中文也必须是GBK编码才可正常显示,不然报错。windows

3.选择一款好的IDE,设置一款独特的凸显品味的字体与配色,可以让初学者前期愉快地被编码问题搞崩,而不是恼火地崩掉,也能帮助你很好的管理代码。(推荐PyCharm,有免费版)函数

设置默认编码

import sys
reload(sys)
sys.setdefaultencoding( "utf-8" )

  以上代码将系统编码由ASCII码转为UTF-8编码。reload(sys)是由于import时将setdefaultencoding()方法删除了,因此将其从新载入回来。为何说ascii是系统默认编码,由于当你使用str()给字符串encode或者是unicode()来decode时,都是默认使用了ASCII码,所以常常会报出相似"UnicodeDecodeError: 'ascii' codec can't decode byte 0xd1 in position 0"的错误,缘由就是字符串里掺杂了中文,前面说到ascii码是不支持中文的。若是把系统默认编码设置为utf-8,就不会出现这样的问题了哦~
  那么,它与脚本开头的"# -*- coding:utf-8 -*-"有什么区别呢,注意,脚本开头的编码申明只是针对在脚本中输入的非英文、数字、符号的字符串如中文,将其存成utf-8的形式,而非系统转码的形式。
  当开头设置默认编码时,很容易出现程序运行到setdefaultencoding就默认终止的状况(IDLE下),这时候须要在reload先后加入这个,目的是为了从新定向,防止reload将变量重置:性能

stdout = sys.stdout
reload(sys)
sys.stdout = stdout

IO时的编码问题

  • txt
      1.写txt文件时,windows下默认会写出为ANSI编码,在windows系统下就是GBK编码。若是字符串被encode为utf-8,那么写出的txt则为utf-8,可是当字符串为unicode时,若是有中文,写出会报错,缘由就是按照系统默认编码ascii进行编码了,按以前所说的将默认编码改成utf8就没问题了,但输出的也变成了utf-8。若是想写入unicode,须要借助codecs库的open方法,读者能够自行百度。
      2.读取txt文件时,若是txt文件为ANSI码,则读入的为gbk编码,可用gbk解码;若是txt文件为utf-8编码,则读入的也为utf-8编码;而若是txt为unicode时,咱们会发现一个奇怪的现象,读入的文本编码变成了"utf-16",因此须要用utf-16解码(至于为何留给读者探索)。
  • csv
      写出csv时,注意utf-8编码和gbk编码是不能用制表符\t进行分列的(excel显示时),必须使用逗号,不然没法显示分列结果。windows下推荐用gbk写出,不然中文容易乱码。固然,若是是包含大量文本的数据,很是不推荐使用csv输出,一不当心就错位,直接输出excel是不错的选择。
  • excel
    xlrd,xlwt,xlsxwriter都是很是好的excel读写库,xlrd目前支持读写xlsx(2007版)与xls(2003版),xlwt只支持写出2003版xls,xlsxwriter支持2007版的写出,并且输入字符串均须要时unicode编码才行,不然报错。

网页抓取时的编码问题

  网页抓取时遇到的主要问题,无非是网页源代码中掺杂了为被转义的编码形式,被做为纯文本读了进来,好比这样一个字符串"\u6768\u777f",不管怎么print 它都是这个形式由于它是文本,不是编码,那么怎么转为中文呢,则须要用以下命令:字体

print text.decode('unicode_escape')

  很是生动形象的,这句话至关因而把“逃离”掉的unicode编码进行再编码,因而就获得了咱们想要的中文。
  
  一样,有的网页中的文字是以反斜杠加三个数字形式呈现的,这个是标准的八进制字符串,如"\345\244\247",则表示一个中文字;而utf-8的表现形式为16进制字符串,像"\xe6\x9d\xa8"就表明着一个字 ,对于这些字符,只须要使用以下命令便可从文本转为编码字符串:

print text.decode('string_escape')

可是,python使用中还有诸多编码问题,在此推荐个人好友何燕杰的脚本解释型语言Cygnus,目前整个语言正处于开发与调试阶段,完善后将会在博客园里给出。我为此开源项目贡献了很是简洁易用、强大的爬虫库(Requests),因为和c#完美对接,几乎没有任何编码问题。你们敬请期待!

本博原创做品仅供品读,欢迎评论,未经本人赞成谢绝转载。特此申明!

相关文章
相关标签/搜索