Encode

Encode

by kinsly

本文的内容均基于python3.5

编码一直是python中的大坑,反正我是一直没搞明白,今天在做爬虫的时候,觉得实在是有必要把这些东西整理一下。

什么是编码

简单的来说就是,为了是计算机能够表达不同的文字,人们制定了一些表达字母符号的方法,常见的编码有ASCII,utf-8,汉字常见的有GBK,big5, GB18030。也就是说字符必须编码后才能被计算机所处理,计算机使用的缺省编码方式也就是计算机的内码。具体细节参见UNICODE,GBK,UTF-8区别

Unicode

Unicode是国际组织设计的,包括了世界上所有语言文字的编码方案。那么Unicode只是一种编码方案,并没有规定如何传输,保存编码。所以这就是为什么我们有UTF-8,UTF-7,UTF-16,这几种都是按照unicode设计,不同的具体编码方案。为什么UTF-8是比较常见的呢,是因为UTF-8与ISO-8859-1完全兼容。世界上有两个设计unicode的组织,一个是软件制造商协会,另一个是ISO,所以UTF-8好在能够兼容两个协会的标准。UTF-8是以8位为单元对UCS进行编码。

内码

windows目前已经支持unicode,但是很多文档和程序都是采用特定编码系统。所以我们在使用某些软件的时候,必须将unicode转化为软件支持的编码。如word只支持gb2312,但是好像也能识别unicode。所以如果想输出csv然后用word打开,需要转化为GBK或者GB18030,或者BOMUTF-8。BOM的意思是 Byte order Mark

Python 遇到的问题

UnicodeDecodeError: 'charmap' codec can't decode byte X in position Y: character maps to $<$undefine$>$

这个问题一般来说是在输出的时候,没有对输出的内容进行encode,也就是说计算机内部存储的是unicode,而你需要对其进行encode。

data_df.to_csv('some2.csv',encoding='gb18030')

或者是当你读取unicode保存的文件的时候,如json,你也需要对其进行转码。

with open('a.json',encoding="utf-8") as data_file:    
    data = json.load(data_file)

UnicodeEncodeError: 'gbk' codec can't encode character '\ufeff' in position 10: illegal multibyte sequence

这种问题往往是你确定的这种编码方式不能识别数据中的某些编码,也不一定是都识别不了,这时可以换一种编码方式,如GB18030之类的

TypeError: a bytes-like object is required, not 'str'

这个好像是,在读写的时候,要把str转化成编码,也就是二进制之类的,需要进行decode

TypeError: Expected String or Unicode

在用pandas读取json会出现,也可能是没有encoding的问题

设置默认encoding方式

import sys

reload(sys)

sys.setdefaultencoding('utf-8')

在python2.7有这样的用法,但是由于有些包默认不一定是utf-8,所以最好还是不要这样写。

核心三原则

  • 因为某些原因, python 打开流读取出的是str,所以用你知道的每一种编码把它解码成unicode
  • 大概是因为同样的原因,python 的输出也是str, 但是任何一个unicode 只有到要输出的时候才编码成str
  • 在此之间,放弃该死的str,忘了它,当你开始处理的时候,确保你的每一个字符串对象都是unicode

这是segmentfault上一篇文章上说的,感谢作者。题目是python编码的意义
不过好像python3已经没有了这种问题

你导入的好几个模块我都没用过....不过能看出来是跳进了python2的encoding大坑了-_-
总之,研究了近百篇文章后我才意识到,破解encoding问题不用那么复杂.
不用''.encode().decode(),也不用sys.setdefaultencode之类
只要你在全文里除了最后输出部分,保证其余每一个字符串全都是unicode格式就行了.
比如直接手写的字符串你好,就要写成u'你好'
在比如,合并数组为字符串时, 就u''.join(arr)
其余的就unicode(s)
最后实在不行了才.decode().encode()
至于codex模块和charset, ccharset等检测字符串编码的,遇到中文一样傻眼,劝别试.

看到另一个回答,这样说,其实也挺有道理,就是不想太纠结,就不要搞太复杂。简单粗暴

decode & encode

通常我们需要decode()与encode()来进行解码与编码

decode     encode

str ---------> unicode ---------->str

在python2中,编码之间的转换需要通过unicode,所以假如你想将由gbk编码的字符串转换为utf-8编码,需要先将其转换为unicode,再将其转换为utf-8编码的字符串

u = u'中文' #显示指定unicode类型对象u
str = u.encode('gb2312') #以gb2312编码对unicode对像进行编码
str1 = u.encode('gbk') #以gbk编码对unicode对像进行编码
str2 = u.encode('utf-8') #以utf-8编码对unicode对像进行编码
u1 = str.decode('gb2312')#以gb2312编码对字符串str进行解码,以获取unicode
u2 = str.decode('utf-8')#如果以utf-8的编码对str进行解码得到的结果,将无法还原原来的unicode类型

而在python3中,取消了unicode类型,代替它的是使用unicode字符的字符串类型(str),也就是说,上面的说明可以转化为下面这种形式

 decode           encode

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

u = '中文' #指定字符串类型对象u
str = u.encode('gb2312') #以gb2312编码对u进行编码,获得bytes类型对象str
u1 = str.decode('gb2312')#以gb2312编码对字符串str进行解码,获得字符串类型对象u1
u2 = str.decode('utf-8')#如果以utf-8的编码对str进行解码得到的结果,将无法还原原来的字符串内容

具体可参见python encode和decode函数说明

个人经验

用pandas的函数,

df.to_csv('a.csv', encoding='gbk')

可能会方便一点。或者

df.to_csv('a.csv', encoding='gbk',mode = 'a')

这样可以接着写,类似于append的功能

当然也可以直接csv包中的函数直接保存

with open('m.csv','w',encoding = 'utf-8') as f:
    writer = csv.writer(f)
    for i in range(1,len(data_total)):
        writer.writerow(data_total)

但是这样存储出来的csv用word打开可能是乱码。这时候可以用记事本将其打开,另存为的时候将其编码格式修改为unicode,这样我的word就能识别这些数据

致谢:谢谢汪老师在这个过程之中的帮助。

reference:

  1. UNICODE,GBK,UTF-8区别 http://www.cnblogs.com/cy163/archive/2007/05/31/766886.html
  2. python编码的意义 https://segmentfault.com/a/1190000004166137
  3. https://segmentfault.com/q/1010000004620523
  4. http://stackoverflow.com/questions/3218014/unicodeencodeerror-gbk-codec-cant-encode-character-illegal-multibyte-sequen
  5. python encode和decode函数说明 http://www.cnblogs.com/evening/archive/2012/04/19/2457440.html

posted on 2017-01-10 11:46  kinsly  阅读(82)  评论(0编辑  收藏  举报

导航