python: 编码问题

什么是编码

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

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

    • 此时,该字符串可以随意decode(解码)和encode(编码),不会报错,甚至不会进行任何变动,永远都是ascii码,type类型是str
    • 如果在输入该字符串时加入了Unicode申明,即 u"balabala",那么此时字符串type格式为Unicode,可以随意encode,不可decode,但是无论encode成什么,python还是都会以ascii的形式存储
  • 如果输入了中文,那么情况一下子就变得复杂起来。此时必须进行编码申明,否则会抛出如下错误:“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

注意:

  • chardet库的detect方法可以得到字符串的编码类型,当输入字符串为unicode时程序报错,有时候也会误判,置信水平小鱼0.7则不可轻信了。
  • 上述只针对在非DOS中执行py文件时适用:如果是在IDLE中单步执行,则中文字符串是以系统默认编码(windows-1252)保存;如果是在DOS界面中运行,则为GBK编码,而且中文也必须是GBK编码才可正常显示,否则报错。
  • 选择一款好的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')
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,723评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,485评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,998评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,323评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,355评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,079评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,389评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,019评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,519评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,971评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,100评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,738评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,293评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,289评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,517评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,547评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,834评论 2 345

推荐阅读更多精彩内容

  • 几个基本概念 bit二进制位, 是计算机内部数据储存的最小单位,11010100是一个8位二进制数。一个二进制位只...
    西电大侠阅读 3,559评论 1 8
  • 字符集和编码简介 在编程中常常可以见到各种字符集和编码,包括ASCII,MBCS,Unicode等字符集。确切的说...
    兰山小亭阅读 8,456评论 0 13
  • 可以看我的博客 lmwen.top 或者订阅我的公众号 简介有稍微接触python的人就会知道,python中...
    ayuLiao阅读 3,094评论 1 5
  • 继上一篇文章字符集和编码详解总结了常见字符编码后,这篇文章会对python中常见的编码问题进行分析和总结。由于py...
    __七把刀__阅读 2,890评论 0 6
  • 人在身体健康时从来不会考虑到生病后是什么样的,只有在生病时才明白健康的可贵,这句话大家都听腻了,就成了常识...
    思维灯泡阅读 661评论 0 1