Encode

by kinslyhtml

本文的內容均基於python3.5python

編碼一直是python中的大坑,反正我是一直沒搞明白,今天在作爬蟲的時候,以爲實在是有必要把這些東西整理一下。json

什麼是編碼

簡單的來講就是,爲了是計算機可以表達不一樣的文字,人們制定了一些表達字母符號的方法,常見的編碼有ASCII,utf-8,漢字常見的有GBK,big5, GB18030。也就是說字符必須編碼後才能被計算機所處理,計算機使用的缺省編碼方式也就是計算機的內碼。具體細節參見UNICODE,GBK,UTF-8區別segmentfault

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

內碼

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$>$app

這個問題通常來講是在輸出的時候,沒有對輸出的內容進行encode,也就是說計算機內部存儲的是unicode,而你須要對其進行encode。python2.7

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 sequenceui

這種問題每每是你肯定的這種編碼方式不能識別數據中的某些編碼,也不必定是都識別不了,這時能夠換一種編碼方式,如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
相關文章
相關標籤/搜索