記錄一些之前遇到的編碼解碼方法,當速查表。
如果誰有更好的方法歡迎留言告知。
URL編碼
‘%E4%BD%A0’【urllib.request.unquote(xxx)】
很常見,你用百度隨便搜點什麼,在看一下上面的地址欄裏面,你要搜索的文字就是被轉碼成這種格式的。
解碼:
>>> import urllib.request
>>> urllib.request.unquote('http%3a%2f%2fwww.baidu.com%2fs%3fwd%3d%E4%BD%A0%E5%A5%BD')
'http://www.baidu.com/s?wd=你好'
#如果用的是requests庫,則
>>> import requests
>>> requests.utils.unquote()
編碼:
>>> import urllib.request
>>> urllib.request.quote('你好')
'%E4%BD%A0%E5%A5%BD'
題外話:
電腦裏翻到不知道多少年前的通訊錄備份文件(*.vcf),想看看都有啥。用文本編輯器打開發現姓名的編碼都顯示成=E5=8D=8E=E4=B8=BA
這種格式。
vcf = '''BEGIN:VCARD
VERSION:2.1
N;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:;=E5=BE=AE=E6=98=9F=E5=94=AE=E5=90=8E=E7=BB=B4=E4=BF=AE=E7=AB=99;;;
FN;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:=E5=BE=AE=E6=98=9F=E5=94=AE=E5=90=8E=E7=BB=B4=E4=BF=AE=E7=AB=99
TEL;WORK:010 6250 9074
ORG;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:=E5=8C=97=E4=BA=AC=E4=B8=AD=E5=85=B3=E6=9D=91=20=E5=8C=97=E4=BA=AC=E5=
=B8=82=E6=B5=B7=E6=B7=80=E5=8C=BA=E4=B8=AD=E5=85=B3=E6=9D=91=E7=A7=91=
=E5=AD=A6=E9=99=A2=E5=8D=97=E8=B7=AF=35=35=E5=8F=B7=C2=A0
END:VCARD
BEGIN:VCARD
VERSION:2.1
N;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:=E5=8D=8E=E4=B8=BA;=E5=AE=A2=E6=9C=8D;;;
FN;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:=E5=8D=8E=E4=B8=BA=E5=AE=A2=E6=9C=8D
TEL;CELL:4008308300
EMAIL;HOME:[email protected]
ADR;WORK;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:;;=E6=B7=B1=E5=9C=B3=E5=B8=82=E9=BE=99=E5=B2=97=E5=8C=BA=E5=9D=82=E7=94=
=B0=E5=8D=8E=E4=B8=BA=E5=9F=BA=E5=9C=B0;;;;
ADR;WORK;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:;;=E6=B7=B1=E5=9C=B3=E5=B8=82=E9=BE=99=E5=B2=97=E5=8C=BA=E5=9D=82=E7=94=
=B0=E5=8D=8E=E4=B8=BA=E5=9F=BA=E5=9C=B0;;;;
END:VCARD'''
看到CHARSET=UTF-8這種寫法,果斷試着把=
替換成%
,發現還真就是url編碼。
寫個小程序運行一下
import re
import urllib.request
vcf = vcf.replace('=\n=','=')
names = re.findall('(=[\w=]+)',vcf)
for name in names:
if name[3:4]=='=':
name_new = name.replace('=','%')
name_new = urllib.request.unquote(name_new)
vcf = vcf.replace(name,name_new,1)
print(vcf)
然後一目瞭然。
BEGIN:VCARD
VERSION:2.1
N;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:;微星售後維修站;;;
FN;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:微星售後維修站
TEL;WORK:010 6250 9074
ORG;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:北京中關村 北京市海淀區中關村科學院南路55號
END:VCARD
BEGIN:VCARD
VERSION:2.1
N;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:華爲;客服;;;
FN;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:華爲客服
TEL;CELL:4008308300
EMAIL;HOME:mobile@huawei.com
ADR;WORK;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:;;深圳市龍崗區阪田華爲基地;;;;
ADR;WORK;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:;;深圳市龍崗區阪田華爲基地;;;;
END:VCARD
Unicode編碼
\u6ee1【xxx.encode().decode(‘unicode_escape’)】
有些時候你會遇到這樣的文字
{"dataHtml":"<li …… 38371c4c411.jpg\" alt=\"\u6ee1\u6c49\u5168\u5e2d\"\/><\/a><p class=\" …… }
‘\uxxxx’在實際生活遇到的很多都是中文的Unicode編碼。一般用json模塊加載的時候,可以自動轉換處理的。如果不是在json中遇到的,可以這樣解碼:
>>> r'\u6ee1\u6c49\u5168\u5e2d'.encode().decode('unicode_escape')
滿漢全席
html轉義字符
& amp ;【html.parser.HTMLParser().unescape(xxx)】
因爲&等字符在html代碼中是有特殊含義的符號,因此作爲文字顯示的時候,在源代碼中用轉義字符的方式顯示。
解碼方式如下:
>>> import html.parser
>>> html_parser = html.parser.HTMLParser()
>>> html_parser.unescape('~^ω^~')
'~^ω^~'
有的網頁比較噁心,還會遇到二次轉義的,比如&omega;
這種。對於需要處理多次的,直接寫了個函數。
import html.parser
def html_unescapeEntities(string):
str_new = string
str_old = ''
while str_old != str_new:
str_old = str_new
str_new = html.parser.HTMLParser().unescape(str_old)
return str_new
>>> html_unescapeEntities('&omega;')
'ω'
# 成功得到字符ω
至於編碼,試着用encode方法寫出來了,實際使用中還沒遇到過非要手動轉義的情況:
>>> str('ω'.encode('ascii', 'xmlcharrefreplace'),'ascii')
'ω'
字節集
b’\xd5\xfd’【xxx.decode([encoding])】
先說一下怎麼解碼的
如果是在網頁中遇到的,看一下網頁源代碼通常會有這樣的東西:
<meta http-equiv="content-type" content="text/html;charset=gb2312">
其中charset
就是編碼格式,參照下面的寫法解碼就行了。
>>> b'\xd5\xfd'.decode('gb2312')
'正'
說幾句廢話。
偶爾碰到有人問\xbb\xbb這個怎麼解碼,我覺得最好是先明確這麼一個概念:
b’\xd5\xfd’ 是純粹計算機的數據格式。
你要說它是數字,也可以。它就是16進制的 d5fd,二進制的 1101010111111101。文字要經過編碼才能存到計算機裏,我想你一定還記得電腦只能存’01010101’這回事吧。
那磁盤或內存上的’0101’是怎麼轉換爲文字呢?
看過諜戰片的都知道,電視劇裏情報員通過電臺聽到“3379 3728”之類密碼後,拿着一本書按照數字指定的頁數行數把密碼翻譯出來。
解碼也一樣,數字“d5fd”就是密碼,只有當知道解碼的書是《GBK》的時候,你才能正確的解出來。
>>> b'\xd5\xfd'.decode('gbk')
'正'
否則……
>>> b'\xd5\xfd'.decode('big5')
'淏'
>>> b'\xd5\xfd'.decode('IBM1026')
'NÙ'
>>> b'\xd5\xfd'.decode('EUC-KR')
'攣'
>>> b'\xd5\xfd'.decode('EUC_JP')
'屎'
所以問 ”\xd5\xfd是什麼?“ ,就好比在問 “第213頁15行第13字是什麼?” ,這麼點信息鬼知道是神馬啊!屎啊? (╯╰_╯)╯╧╧
但就日常而言,雖然編碼的種類非常多,但我們接觸到的很有限。如果不知道編碼,建議你可以GBK、UTF-8、BIG5挨個試試 (ΦωΦ)。
或者用第三方庫,比如chardet來判斷編碼類型。
>>> import chardet
>>> phase = '使用 chardet 可以很方便的實現字符串/文件的編碼'
>>> aaa = phase.encode('gbk')
>>> bbb = phase.encode('utf-8')
>>> chardet.detect(aaa)
{'encoding': 'GB2312', 'confidence': 0.99}
>>> chardet.detect(bbb)
{'encoding': 'utf-8', 'confidence': 0.99}
看到結論了吧,chardet會很謙虛的對你說”(๑>◡<๑) 我99%肯定這是XX編碼的”。
那麼chardet就一定對嗎?答案是否定的。
chardet從來不100%confidence是什麼編碼,意思就是告訴你還是有可能存在意外的,使用的時候還需注意。比如:
>>> import chardet
>>> phase = '使用 chardet 可以很方便的實現字符串'.encode('gbk')
>>> print(chardet.detect(phase))
{'confidence': 0.99, 'encoding': 'GB2312'}
很明顯這是錯的,因爲gb2312是解不了繁體字的。
GB2312只支持簡體中文,GBK支持簡中、繁中,GB18030支持簡中、繁中、藏文、蒙文、維吾爾文等。也就是說從GB2312(1980年)、GBK(1995年)到GB18030(2000年),這些編碼方法是向下兼容的。
另外,簡體windows下的ANSI同樣表示GB2312。不同的國家和地區制定了不同的標準,由此產生了 GB2312, BIG5, JIS 等各自的編碼標準。這些使用 2 個字節來代表一個字符的各種漢字延伸編碼方式,稱爲 ANSI 編碼。在簡體中文系統下,ANSI 編碼代表 GB2312 編碼,在日文操作系統下,ANSI 編碼代表 JIS 編碼。繁體中文操作系統是BIG5.
跑碼小程序
最後寫個小程序,以後遇到不知道編碼的字節集,大可放進去跑跑試試。
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import chardet
def decodetest1(byte):
aaa='''IBM037|IBM437|IBM500|ASMO-708|DOS-720|ibm737|ibm775|ibm850|ibm852|IBM855|ibm857|IBM00858|IBM860|ibm861|DOS-862|IBM863|IBM864|IBM865|cp866|ibm869|IBM870|windows-874|cp875|shift_jis|ks_c_5601-1987|big5|IBM1026|IBM01047|IBM01140|IBM01141|IBM01142|IBM01143|IBM01144|IBM01145|IBM01146|IBM01147|IBM01148|IBM01149|utf-16|unicodeFFFE|windows-1250|windows-1251|windows-1252|windows-1253|windows-1254|windows-1255|windows-1256|windows-1257|windows-1258|Johab|macintosh|x-mac-japanese|x-mac-chinesetrad|x-mac-korean|x-mac-arabic|x-mac-hebrew|x-mac-greek|x-mac-cyrillic|x-mac-chinesesimp|x-mac-romanian|x-mac-ukrainian|x-mac-thai|x-mac-ce|x-mac-icelandic|x-mac-turkish|x-mac-croatian|utf-32|utf-32BE|x-Chinese_CNS|x-cp20001|x_Chinese-Eten|x-cp20003|x-cp20004|x-cp20005|x-IA5|x-IA5-German|x-IA5-Swedish|x-IA5-Norwegian|us-ascii|x-cp20261|x-cp20269|IBM273|IBM277|IBM278|IBM280|IBM284|IBM285|IBM290|IBM297|IBM420|IBM423|IBM424|x-EBCDIC-KoreanExtended|IBM-Thai|koi8-r|IBM871|IBM880|IBM905|IBM00924|EUC-JP|x-cp20936|x-cp20949|cp1025|koi8-u|iso-8859-1|iso-8859-2|iso-8859-3|iso-8859-4|iso-8859-5|iso-8859-6|iso-8859-7|iso-8859-8|iso-8859-9|iso-8859-13|iso-8859-15|x-Europa|iso-8859-8-i|iso-2022-jp|csISO2022JP|iso-2022-jp|iso-2022-kr|x-cp50227|euc-jp|EUC-CN|euc-kr|hz-gb-2312|gb2312|gbk|GB18030|x-iscii-de|x-iscii-be|x-iscii-ta|x-iscii-te|x-iscii-as|x-iscii-or|x-iscii-ka|x-iscii-ma|x-iscii-gu|x-iscii-pa|utf-7|utf-8'''
for encoding in aaa.split('|'):
try:
sss = byte.decode(encoding)
print('%15s %s'% (encoding,sss))
except:
pass
print(chardet.detect(byte))
def decodetest2(text):
code_arr='''shift_jis|koi8-r|euc-kr|euc-jp|ISO-2022-JP|big5|GB18030|utf-8|utf-16|utf-32'''.split('|')
for c1 in code_arr:
for c2 in code_arr:
if c1!=c2:
try:
sss = text.encode(c1).decode(c2)
print('%10s %10s %s'% (c1,c2,sss))
except:
pass
if __name__ == '__main__':
decodetest1(b'\xba\xf3\xc7\xda\xb9\xdc\xc0\xed')
#decodetest2('鍏抽棴')
結果如下:
…… ……
macintosh ∫Û«⁄π‹¿Ì
x-mac-korean 빈핸밗잿
IBM273 ¬3G¹¾}äÒ
koi8-r ╨Сгз╧эюМ
EUC-JP 朔輩砿尖
koi8-u ╨Сгз╧эюМ
iso-8859-1 ºóÇÚ¹ÜÀí
iso-8859-2 şóÇÚšÜŔí
iso-8859-3 şóÇÚıÜÀí
iso-8859-4 ēķĮÚšÜĀí
iso-8859-5 КѓЧкЙмРэ
iso-8859-7 ΊσΗΪΉάΐν
iso-8859-9 ºóÇÚ¹ÜÀí
iso-8859-13 ŗóĒŚ¹ÜĄķ
iso-8859-15 ºóÇÚ¹ÜÀí
euc-jp 朔輩砿尖
EUC-CN 後勤管理
euc-kr 빈핸밗잿
gb2312 後勤管理
gbk 後勤管理
GB18030 後勤管理
{'confidence': 0.0, 'encoding': None}
[Finished in 0.2s]