什么是编码

  任何一种语言、文字、符号等等,计算都是将其以一种类似字典的形式存起来的,比如最早的计算机系统将英文文字转为数字存储(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代码中输入一个字符串时候,它是以什么编码形式被保存的呢?

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

  • 此时,该字符串可以随意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码无法识别的东西,且没有进行编码申明,所以此时要在文件开头进行编码申明,完整版如下:

#!/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则不可轻信了。

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

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#完美对接,几乎没有任何编码问题。大家敬请期待!

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

Python2 新手 编码问题 吐血总结的更多相关文章

  1. 【Python】python2 str 编码检测

    python2 str 编码检测 import chardet s = 'sdffdfd' print type(s) print chardet.detect(s) s2 = '反反复复' prin ...

  2. 转:Python2字符编码问题汇总

    这篇文章的部分问题在Python3以后不再存在,老猿只是觉得文章的部分内容还是有参考价值,因此在此原文转发连接: Python2字符编码问题汇总

  3. 不想再被鄙视?那就看进来! 一文搞懂Python2字符编码

    程序员都自视清高,觉得自己是创造者,经常鄙视不太懂技术的产品或者QA.可悲的是,程序员之间也相互鄙视,程序员的鄙视链流传甚广,作为一个Python程序员,自然最关心的是下面这幅图啦 我们项目组一值使用 ...

  4. Python2字符编码问题汇总

    目录 从字符编码说起 unicode与utf-8 当编解码遇上Python2.x unicode 与 str 区别 __str__ __repr__的区别 unicode str utf-8关系 un ...

  5. 关于Python2字符编码的体会

    对于Python的字符编码问题也懵了很久,最近做爬虫多次遇到网页转码的问题,干脆彻底解决掉!Just Do it! 1.两种类型str与unicode str和unicode都是basestring的 ...

  6. python2.x编码问题实例

    1,编码问题,主要是区分面向人类的字符串,面向计算机的字节序列 在python3中,字符串是str(默认即unicode),字节序列是bytes 在python2中,字符串是unicode,字节序列是 ...

  7. python2.X编码

    1.Python文件的编码 在Python文件中,可以在第一或第二行指定文件的编码格式(以注释的形式加),这也是Python语法规定的,见http://www.python.org/peps/pep- ...

  8. Python2中编码错误---重组人表皮生长因子凝胶(易孚格式转化为UTF-8

    在python2的使用中,总会遇到各种各样的编码问题,这也是使用Python2最头疼的一件事情,幸好python3解决了编码的问题. 下面我在爬虫时遇到的类似重组人表皮生长 ...

  9. 从python2,python3编码问题引伸出的通用编码原理解释

    今天使用python2编码时遇到这样一条异常UnicodeDecodeError: ‘ascii’ code can’t decode byte 0xef 发现是编码问题,但是平常在python3中几 ...

随机推荐

  1. centos7 开放端口

    开启端口 firewall-cmd --zone=public --add-port=80/tcp --permanent 命令含义:   --zone #作用域   --add-port=80/tc ...

  2. cacti汇总流量图-将数据合并后作图

    在使用Cacti方便快捷的建立监控图时,往往根据实际应用必须监控几台甚至上百台服务器的汇总流量图来观察该应用服务器组的总流量等指标. 这里我们就来介绍如何用cacit快速的建立汇总流量图,其他汇总图建 ...

  3. django rest framework 再撸体验

    曾经了解过. 放在一边,嫌麻烦. 如今身为leader,站在团队沟通的角度看看,还不错. 有几个优点: 1. api一览表 2. api web预览界面(类似.net的webservice预览界面), ...

  4. Nodejs 饭店

     一个Node.js饭店的发展历程 前面的一堆理论似乎不太好明白,最后讲一个关于饭店发展历程的故事作为结尾吧.     第一年 饭店开张,只有一个厨师(同时还兼任老板.服务员.打荷.收银员),当一个客 ...

  5. HDU 2586

    http://acm.hdu.edu.cn/showproblem.php?pid=2586 题意:求最近祖先节点的权值和 思路:LCA Tarjan算法 #include <stdio.h&g ...

  6. selenium 常见面试题以及答案(Java版)

    1.怎么 判断元素是否存在? 判断元素是否存在和是否出现不同, 判断是否存在意味着如果这个元素压根就不存在, 就会抛出NoSuchElementException 这样就可以使用try catch,如 ...

  7. 安卓手机 虚拟键盘输入用 position:fixed解决 !!!

    下面 主要代码 方便看. 样式 <style> *{ margin:0; padding:0; } html{ height:100%;/*关键代码*/ } body{ height:10 ...

  8. MFC操作注册表

    1.创建和修改注册表 BOOL CTestToolCtr::GetHkey(CString strHkey, HKEY& hkey) { == strHkey.CompareNoCase(_T ...

  9. SqlServer -- 仅当使用了列列表并且 IDENTITY_INSERT 为 ON 时,才能为表'T_FM_AMTFLOW'中的标识列指定显式值。

    SET IDENTITY_INSERT TABLE_NAME ON; INSERT INTO TABLE_NAME(XXX, XXX,..., XXX) SELECT XXX, XXX,..., XX ...

  10. 解决浏览器Adobe Flash Player不是最新版本问题

    关键:选择谷歌浏览器的PPAPI版本的flash下载直接安装即可 搜索: Adobe Flash Player PPAPI 下载地址: http://www.wmzhe.com/soft-30259. ...