python2编码_Python2字符编码
我們通常見(jiàn)到的字符串編碼主要是三種GB2312/GBK、Unicode、UTF-8。GB2312/GBK是多字節(jié)(multibytes)編碼的一種,屬于“ASCII的加強(qiáng)版”,與之平行的由Big5、ShiftJIS之類的編碼各自為政,所有這些用兩個(gè)字節(jié)表示漢字的多字節(jié)編碼標(biāo)準(zhǔn)統(tǒng)稱為ANSI編碼,同樣的漢字在不同的ASNI編碼中的表示是不同的。為了避免這個(gè)問(wèn)題,Unicode應(yīng)運(yùn)而生,將全世界所有的字符統(tǒng)一編碼到一個(gè)定長(zhǎng)的結(jié)構(gòu)中。Unicode解決了統(tǒng)一編碼的問(wèn)題,但帶來(lái)了新的問(wèn)題。第一點(diǎn),Unicode和ASCII不兼容了,這是因?yàn)锳SCII只有一個(gè)字節(jié),而這一個(gè)字節(jié)肯定裝不下Unicode。第二點(diǎn),用Unicode傳輸開(kāi)銷變大了,這是因?yàn)楹芏辔臋n二十六個(gè)字母(1個(gè)字節(jié))就能解決了,用Unicode多了很多冗余的字節(jié)。因此UTF-8應(yīng)運(yùn)而生。UTF-8對(duì)Unicode進(jìn)行變長(zhǎng)編碼(我們可以想象下Huffman樹(shù)),通常長(zhǎng)度在1-4字節(jié)。目前Linux系統(tǒng)使用的是UTF-8編碼,而Windows內(nèi)部則是UTF-16LE/GBK編碼。
Python2的字符串表示
Python2中有表示字符串有str和Unicode兩種。其中一個(gè)str字面量由""表示,我們也可以用''或者"""這類括號(hào)括起,一個(gè)Unicode字面量由u""括起。1
2
3
4
5
6
7
8"你好"
'xc4xe3xbaxc3'
u"你好"
u'u4f60u597d'
type("你好")
type(u"你好")
其中Unicode得益于ucs2/ucs4標(biāo)準(zhǔn),在不同系統(tǒng)上都是固定的表示的。其中ucs2即Unicode16,比較常見(jiàn),用2個(gè)字節(jié)(65536)來(lái)索引,一般表示是u"uxxxx",ucs4即Unicode32,一般表示是u"Uxxxxyyyy"在一些Python中也能見(jiàn)到。我們可以通過(guò)下面的代碼來(lái)檢測(cè)Python是哪一個(gè)1
2
3
4
5
6
7
8
9--enable-unicode=ucs4
>>> import sys
>>> print sys.maxunicode
1114111
--enable-unicode=ucs2
>>> import sys
>>> print sys.maxunicode
65535
str的表示取決于所在的系統(tǒng),例如Linux是默認(rèn)UTF8,上面的“你好”就會(huì)變?yōu)?#39;/xe4/xbd/xa0/xe5/xa5/xbd',我們這里看到UTF8確實(shí)是一種字符的表示。1
2
3
4
5
6
7
8
9
10
11>>> "hello".encode("utf-8")
'hello'
>>> "hello".decode("gbk").encode("utf-8")
'hello'
>>> "你好".encode("utf-8")
Traceback (most recent call last):
File "", line 1, in
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc4 in position 0: ordinal not in range(128)
>>> "你好".decode("gbk").encode("utf-8")
'xe4xbdxa0xe5xa5xbd'
Python2中字符串問(wèn)題實(shí)錄
reload
在Python2中出現(xiàn)編碼問(wèn)題時(shí),很多人喜歡使用下面的語(yǔ)句來(lái)改變系統(tǒng)的默認(rèn)編碼1
2
3import sys
(sys)
sys.setdefaultencoding('utf-8')
這種策略通常用來(lái)解決下面這樣的錯(cuò)誤提示
UnicodeEncodeError: 'ascii' codec can't encode byte
現(xiàn)在ASCII碼不能encode是吧,那我默認(rèn)都用utf-8來(lái)encode總行了吧?但這樣可能存在問(wèn)題,博文中就舉出了一個(gè)實(shí)例。對(duì)于多字節(jié)字符串str,我們之前默認(rèn)用ASCII解碼,要是解不開(kāi),就RE了。現(xiàn)在我們默認(rèn)用utf-8解,utf-8閾值廣,基本都能解開(kāi),不RE了,可是就不WA了么?樣例中舉出一個(gè)例子,一個(gè)latin-1編碼的字符串,用utf-8解碼不會(huì)報(bào)錯(cuò),但解出來(lái)的結(jié)果并不對(duì)。因此在多字節(jié)編碼規(guī)則不統(tǒng)一這個(gè)客觀問(wèn)題存在的情況下,不存在銀彈。我們需要的是用chardet.detect來(lái)猜測(cè)編碼。當(dāng)猜測(cè)不出時(shí)我們只能不停地try,直到找到一個(gè)解碼不報(bào)錯(cuò)的編碼,雖然可能解出來(lái)還是亂碼,因?yàn)榭赡芤欢蝏yte串同時(shí)用utf-8、gbk、Big5等都能解碼而不報(bào)錯(cuò)。
這里提供一個(gè)工具類,能夠盡可能地猜測(cè)字節(jié)串所使用的編碼1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23def ultimate_decode(doc):
def try_decode(s, try_decoding):
try:
res = s.decode(try_decoding)
return True, res
except UnicodeDecodeError:
return False, ""
if isinstance(doc, str):
predicted = chardet.detect(doc)
print predicted
if predicted['encoding'] and predicted['confidence'] > 0.5:
doc = doc.decode(predicted['encoding'])
else:
encodeing_list = ["utf-8", "gbk", "Big5", "EUC-JP"]
for e in encodeing_list:
state, res = try_decode(doc, e)
if state:
doc = res
break
if not isinstance(doc, unicode):
return None
return doc
coding
當(dāng)我們?cè)赑ython代碼文件中需要加入中文時(shí),我們需要在文件開(kāi)頭加上這兩行中的一行,不然即使用上前面的reload大法都不行。1
2#-*- coding:utf-8 -*-
#coding: utf8
這是用來(lái)指定Python代碼文件所使用的編碼方式。在Python2.1時(shí),這個(gè)機(jī)制還沒(méi)有引入,我們只能通過(guò)unicode-escape的方式輸入。一個(gè)類似的做法是很多json庫(kù)dump的結(jié)果中常出現(xiàn)u打頭的unicode-escape字符串,這是非常正常的現(xiàn)象。這樣json庫(kù)可以省事地避免編碼問(wèn)題,因?yàn)檫@樣json文件現(xiàn)在都是ASCII碼了。
偽裝成Unicode的多字節(jié)
有時(shí)候我們會(huì)看到這種東西u'xe3x80x8axe5',首先這外面套了個(gè)u,應(yīng)該是Unicode,但是里面卻是x打頭的multi-bytes的形式,這往往是由于錯(cuò)誤調(diào)用unicode()函數(shù)所致的。對(duì)此,python提供了raw_unicode_escape來(lái)解決這個(gè)問(wèn)題
正則匹配
由于存在特殊符號(hào)的原因,使用正則匹配時(shí)宜使用Unicode而不是多字節(jié)匹配。但是以下的編碼在Win10和某些Linux發(fā)行版上都跑不了,但在MacOS和Ubuntu上能夠正常運(yùn)行,去StackOverflow問(wèn)了,他們認(rèn)為這是一個(gè)Bug,所以暫時(shí)還是先用上面的方法。
總結(jié)
以上是生活随笔為你收集整理的python2编码_Python2字符编码的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: dependency报错
- 下一篇: websocket python爬虫_p