五分鐘戰(zhàn)勝Python字符編碼

對于很多接觸Python的人而言芬萍,字符的處理和語言整體的溫順可靠相比顯得格外桀驁不馴難以駕馭。

本文不談復(fù)雜的理論,就經(jīng)驗教你字符處理八字真言:確定編碼蜓谋,同類交互。

文章針對Python 2.7炭分,主要因為3對的編碼已經(jīng)有了很大的改善并且實際原理一樣桃焕,更改一下操作命令即可。

了解完本文捧毛,你可以輕松解決文字處理观堂,特殊平臺(Windows?)下的編碼,爬蟲編碼等問題呀忧。

閱讀建議

本文分為如下幾個部分:

  • 原理
  • 具體操作
  • 建議的使用習(xí)慣
  • 疑難問題解答

如果想要了解我給出的使用習(xí)慣师痕,可以直接跳到建議的使用習(xí)慣。

如果只想要解決相關(guān)問題可以直接跳到疑難問題解答而账。

希望本文能夠幫到你胰坟。

原理

為了理解方便,這里不談理論只做類比泞辐,具體想要進一步了解各種編碼的理論的搜狗一下好了笔横。

首先說一下我們?yōu)槭裁磿龅礁魇礁鳂拥木幋a問題:

  • 因為我們沒有統(tǒng)一編碼
  • 因為我們沒有用對命令(傳對數(shù)據(jù))

再說一下編碼是什么,Python的編碼看似復(fù)雜咐吼,實際上可以看做只有兩類編碼:Unicode吹缔,二進制

  • Unicode 相信都很熟悉:,就是\u0000這樣的
  • 二進制編碼也很簡單锯茄,就是\x00\x00這樣的厢塘,平巢杳唬看到的utf-8,cp936都是二進制編碼
  • 二進制編碼是具象的,10001100原樣就可以存儲晚碾,而Unicode是抽象的抓半,不能這樣存
#coding=utf8

# Unicode編碼演示
print('Unicode:')
print(repr(u'Unicode編碼'))`

# 二進制編碼演示
print(u'二進制編碼:')
print(repr('Unicode編碼'))`

# 只是看個樣子,代碼不必去深究

再說怎么做格嘁,就是只有同種編碼之間才可以操作

  • 舉個簡單的類比
就把一串?dāng)?shù)據(jù)比為烤鴨琅关,我們作為人和鴨子不同種看待烤鴨的態(tài)度完全不一樣。
我們看到的是晚上的配菜讥蔽,鴨子看到的是自己二舅涣易。
那么我在逛烤鴨店的時候用錯編碼就會報錯。
因為我在烤鴨店看到了滿世界的二舅冶伞。
  • 這里說的同種就是我們熟悉的各種編碼方式:utf-8,unicode,ucs-bom
  • 這也就是編碼問題的核心逼侦,非常重要峡懈。

最后說一下Python的環(huán)境

  • 本身代碼是用Ascii解碼的吨艇,文件里有Ascii無法解碼的內(nèi)容的話要告知Python怎么解碼
  • 內(nèi)部大量命令都是默認接受Unicode
# 告知的命令就是下面這一行嘉蕾,刪掉就會報錯
#coding=utf8
print(u'測試編碼')

具體操作

拿到各種編碼的內(nèi)容自然是不用說,那么如果我們想要自己構(gòu)造怎么做呢芋类,看下面:

#coding=utf8

# 字符串前面加u會默認構(gòu)造出Unicode的字符串
unicodeString = u'Unicode字符串'

# 字符串前面什么都不加會構(gòu)造出默認編碼(首行限定了現(xiàn)在的utf8)的字符串
utf8String = 'Utf-8字符串'

# 當(dāng)然隆嗅,沒有首行,默認的編碼是Ascii

那么他們之間怎么轉(zhuǎn)換呢侯繁,同樣很簡單:

# 接上一段程序

# Unicode轉(zhuǎn)化為二進制編碼中的一種:utf8
unicodeString.encode('utf8')

# 二進制編碼根據(jù)自己的編碼種類轉(zhuǎn)化為Unicode
utf8String.decode('utf8')

# 如果二進制編碼中混進了奇怪的東西可以根據(jù)需求用特殊的decode策略
print(repr('u8字\x00符串'.decode('utf8', 'replace')))

那么怎么樣會出現(xiàn)問題呢:

# 接上一段程序

# 如果我們把他們轉(zhuǎn)化成同樣的編碼方式就可以操作(例如相加)
print(repr(unicodeString + utf8String.decode('utf8')))
print(repr(unicodeString.encode('utf8') + utf8String))

# 但如果不轉(zhuǎn)化胖喳,當(dāng)然就會出現(xiàn)滿世界的烤鴨二舅啦
unicodeString + utf8String

# 所以另一方面也發(fā)現(xiàn),編碼轉(zhuǎn)換是需要我們告訴程序怎么做的
# 所有`decode`操作都會生成Unicode編碼贮竟,這是為了方便我之前說的大量接受Unicode的內(nèi)部命令

所以我們需要確定程序使用的編碼丽焊,這是我們需要告訴程序的東西

  • 一方面在操作字符串的時候確定是同種編碼
  • 另一方面在使用非自己寫的命令時,一般使用Unicode咕别,或者使用接收二進制編碼的命令
#coding=utf8
# 這里拿寫入文件舉例

# 一般使用Unicode
with open('Unicode.txt', 'w') as f: f.write(u'Unicode測試')

# 或者使用接收二進制編碼的命令
with open('Utf8.txt', 'wb') as f: f.write('Utf8測試')

# 你可以反過來做個測試技健,自然會報錯
# 二進制的命令方便了在不知道怎么解碼的情況下也能進行操作(寫入文件)

我建議的使用習(xí)慣

相信到這里我已經(jīng)把我對于編碼的理解講完了。

我們?yōu)槭裁磿龅礁魇礁鳂拥木幋a問題:

  • 因為我們沒有統(tǒng)一編碼
  • 因為我們沒有用對命令(傳對數(shù)據(jù))

所以這里再重申一下八字真言:確定編碼惰拱,同類交互

  • 碰到問題雌贱,問一下自己,我現(xiàn)在是哪種編碼
  • 同一種編碼才能交互偿短,那我應(yīng)該是哪種編碼

這里給出我的使用習(xí)慣:

  • 確定一種內(nèi)部編碼
  • 內(nèi)部編碼的選擇優(yōu)先級如下:程序必須使用的編碼欣孤、第三方包使用的編碼、你喜歡的編碼翔冀、Unicode
  • 在輸出時再更改到特定的編碼

記得在開始整個程序之前確定內(nèi)部的編碼导街,否則編碼一團糟會產(chǎn)生很多不必要的bug披泪。

不要迷信內(nèi)部Unicode纤子,例如Evernote開發(fā)就應(yīng)該根據(jù)第三方包使用的Utf8確定內(nèi)部編碼。

疑難問題解答

編碼識別

說了要確定編碼,那么拿到一串二進制要怎么確定編碼呢控硼?

最簡單的方法是chardet:(需要安裝)

python -m pip install chardet

使用非常簡單:

#coding=utf8

from chardet import detect
print(detect('這是一串utf8的測試字符'))

# 結(jié)果:`{'confidence': 0.99, 'encoding': 'utf-8'}`

另外例如抓取網(wǎng)站泽论,那么頭文件中很有可能有提示如何解碼,記得不要忘記了卡乾。

編碼轉(zhuǎn)換

很可能因為字符串中參雜了奇怪的東西翼悴,導(dǎo)致即使編碼種類正確,依舊無法解碼幔妨。

我知道我之前講過了鹦赎,但可能有人直接跳疑難問題解答嘛。

這里可以使用decode的第二個參數(shù):

#coding=utf8

# 字符串中混進了\x00
rubbishUtf8String = 'Utf-8字\x00符串'

print(repr(rubbishUtf8String.decode('utf8', 'replace')))

print(repr(rubbishUtf8String.decode('utf8', 'ignore')))

特殊平臺下編碼

很多人都說Windows是個坑误堡,即使在Python 3下面也一樣古话。

因為中文文件名出來都是亂碼。

這里使用一個取巧的方法:平臺編碼再特殊锁施,起碼命令行讀取和創(chuàng)建一個文件夾不會出亂碼吧陪踩。

import sys, os

for folder in os.walk('.').next()[1]:
    print(folder.decode(sys.stdin.encoding))

同樣的輸入輸出也可以這樣做優(yōu)化:

import sys

def sys_print(msg):
    print(msg.encode(sys.stdin.encoding))

def sys_input(msg):
    return raw_input(msg.encode(sys.stdin.encoding)).decode(sys.stdin.encoding)

文件寫入

如果抓下來一個內(nèi)容不知道怎么解碼,但還是想要寫入文件怎么辦

寫入文件的時候制定用二進制命令即可:

#coding=utf8
import urllib

with open('Utf8.txt', 'wb') as f: f.write('Utf8測試')

# 比如抓了個網(wǎng)頁悉抵,不知道編碼也可以寫入文件進行一系列操作

content = urllib.urlopen('http://www.baidu.com').read()
with open('baidu.txt', 'wb') as f: f.write(content)

裸Unicode字符

Unicode存成六個Ascii字符怎么辦肩狂?其實也可以decode

#coding=utf8
# 這是普通的Unicode
s = u'測'
for i in s: print(i)
print(repr(s))

# 這是裸Unicode,實際存成了六個Ascii
s = repr(s)[2:-1]
for i in s: print(i)
print(repr(s))

# 轉(zhuǎn)化其實也很簡單
s = s.decode('unicode-escape')
for i in s: print(i)
print(repr(s))

結(jié)束語

希望讀完這篇文章能對你有幫助姥饰,有什么不足之處萬望指正(鞠躬)傻谁。

有什么想法或者想要關(guān)注我的更新,歡迎來GithubStar或者Fork我的項目列粪。

160623

LittleCoder

EOF

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末栅螟,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子篱竭,更是在濱河造成了極大的恐慌力图,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件掺逼,死亡現(xiàn)場離奇詭異吃媒,居然都是意外死亡,警方通過查閱死者的電腦和手機吕喘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進店門赘那,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人氯质,你說我怎么就攤上這事募舟。” “怎么了闻察?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵拱礁,是天一觀的道長琢锋。 經(jīng)常有香客問我,道長呢灶,這世上最難降的妖魔是什么吴超? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮鸯乃,結(jié)果婚禮上鲸阻,老公的妹妹穿的比我還像新娘。我一直安慰自己缨睡,他們只是感情好鸟悴,可當(dāng)我...
    茶點故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著奖年,像睡著了一般遣臼。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上拾并,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天揍堰,我揣著相機與錄音,去河邊找鬼嗅义。 笑死屏歹,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的之碗。 我是一名探鬼主播蝙眶,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼褪那!你這毒婦竟也來了幽纷?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤博敬,失蹤者是張志新(化名)和其女友劉穎友浸,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體偏窝,經(jīng)...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡收恢,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了祭往。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片伦意。...
    茶點故事閱讀 40,090評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖硼补,靈堂內(nèi)的尸體忽然破棺而出驮肉,到底是詐尸還是另有隱情,我是刑警寧澤已骇,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布离钝,位于F島的核電站票编,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏奈辰。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一乱豆、第九天 我趴在偏房一處隱蔽的房頂上張望奖恰。 院中可真熱鬧,春花似錦宛裕、人聲如沸瑟啃。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蛹屿。三九已至,卻和暖如春岩榆,著一層夾襖步出監(jiān)牢的瞬間错负,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工勇边, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留犹撒,地道東北人。 一個月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓粒褒,卻偏偏與公主長得像识颊,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子奕坟,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,033評論 2 355

推薦閱讀更多精彩內(nèi)容