亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > Python > 正文

深入淺析Python字符編碼

2020-01-04 17:56:51
字體:
來源:轉載
供稿:網友

Python的字符串編碼規則一直讓我很頭疼,花了點時間研究了下,并不復雜,本文給大家介紹python字符編碼,感興趣的朋友一起學習吧

Python的字符串編碼規則一直讓我很頭疼,花了點時間研究了下,并不復雜。主要涉及的內容有常用的字符編碼的特點,并介紹了在python2.x中如何與編碼問題作戰,本文關于Python的內容僅適用于2.x,3.x中str和unicode有翻天覆地的變化,具體請查閱相關資料。

1. 字符編碼簡介

1.1. ASCII

ASCII(American Standard Code for Information Interchange),是一種單字節的編碼。計算機世界里一開始只有英文,而單字節可以表示256個不同的字符,可以表示所有的英文字符和許多的控制符號。不過ASCII只用到了其中的一半(/x80以下),這也是MBCS得以實現的基礎。

1.2. MBCS

然而計算機世界里很快就有了其他語言,單字節的ASCII已無法滿足需求。后來每個語言就制定了一套自己的編碼,由于單字節能表示的字符太少,而且同時也需要與ASCII編碼保持兼容,所以這些編碼紛紛使用了多字節來表示字符,如GBxxx、BIGxxx等等,他們的規則是,如果第一個字節是/x80以下,則仍然表示ASCII字符;而如果是/x80以上,則跟下一個字節一起(共兩個字節)表示一個字符,然后跳過下一個字節,繼續往下判斷。

這里,IBM發明了一個叫Code Page的概念,將這些編碼都收入囊中并分配頁碼,GBK是第936頁,也就是CP936。所以,也可以使用CP936表示GBK。

MBCS(Multi-Byte Character Set)是這些編碼的統稱。目前為止大家都是用了雙字節,所以有時候也叫做DBCS(Double-Byte Character Set)。必須明確的是,MBCS并不是某一種特定的編碼,Windows里根據你設定的區域不同,MBCS指代不同的編碼,而Linux里無法使用MBCS作為編碼。在Windows中你看不到MBCS這幾個字符,因為微軟為了更加洋氣,使用了ANSI來嚇唬人,記事本的另存為對話框里編碼ANSI就是MBCS。同時,在簡體中文Windows默認的區域設定里,指代GBK。

1.3. Unicode

后來,有人開始覺得太多編碼導致世界變得過于復雜了,讓人腦袋疼,于是大家坐在一起拍腦袋想出來一個方法:所有語言的字符都用同一種字符集來表示,這就是Unicode。

最初的Unicode標準UCS-2使用兩個字節表示一個字符,所以你常??梢月牭経nicode使用兩個字節表示一個字符的說法。但過了不久有人覺得256*256太少了,還是不夠用,于是出現了UCS-4標準,它使用4個字節表示一個字符,不過我們用的最多的仍然是UCS-2。

UCS(Unicode Character Set)還僅僅是字符對應碼位的一張表而已,比如"漢"這個字的碼位是6C49。字符具體如何傳輸和儲存則是由UTF(UCS Transformation Format)來負責。

一開始這事很簡單,直接使用UCS的碼位來保存,這就是UTF-16,比如,"漢"直接使用/x6C/x49保存(UTF-16-BE),或是倒過來使用/x49/x6C保存(UTF-16-LE)。但用著用著美國人覺得自己吃了大虧,以前英文字母只需要一個字節就能保存了,現在大鍋飯一吃變成了兩個字節,空間消耗大了一倍……于是UTF-8橫空出世。

UTF-8是一種很別扭的編碼,具體表現在他是變長的,并且兼容ASCII,ASCII字符使用1字節表示。然而這里省了的必定是從別的地方摳出來的,你肯定也聽說過UTF-8里中文字符使用3個字節來保存吧?4個字節保存的字符更是在淚奔……(具體UCS-2是怎么變成UTF-8的請自行搜索)

另外值得一提的是BOM(Byte Order Mark)。我們在儲存文件時,文件使用的編碼并沒有保存,打開時則需要我們記住原先保存時使用的編碼并使用這個編碼打開,這樣一來就產生了許多麻煩。(你可能想說記事本打開文件時并沒有讓選編碼?不妨先打開記事本再使用文件 -> 打開看看)而UTF則引入了BOM來表示自身編碼,如果一開始讀入的幾個字節是其中之一,則代表接下來要讀取的文字使用的編碼是相應的編碼:

BOM_UTF8 '/xef/xbb/xbf'

BOM_UTF16_LE '/xff/xfe'

BOM_UTF16_BE '/xfe/xff'

并不是所有的編輯器都會寫入BOM,但即使沒有BOM,Unicode還是可以讀取的,只是像MBCS的編碼一樣,需要另行指定具體的編碼,否則解碼將會失敗。

你可能聽說過UTF-8不需要BOM,這種說法是不對的,只是絕大多數編輯器在沒有BOM時都是以UTF-8作為默認編碼讀取。即使是保存時默認使用ANSI(MBCS)的記事本,在讀取文件時也是先使用UTF-8測試編碼,如果可以成功解碼,則使用UTF-8解碼。記事本這個別扭的做法造成了一個BUG:如果你新建文本文件并輸入"姹塧"然后使用ANSI(MBCS)保存,再打開就會變成"漢a",你不妨試試 :)

2. Python2.x中的編碼問題

2.1. str和unicode

str和unicode都是basestring的子類。嚴格意義上說,str其實是字節串,它是unicode經過編碼后的字節組成的序列。對UTF-8編碼的str'漢'使用len()函數時,結果是3,因為實際上,UTF-8編碼的'漢' == '/xE6/xB1/x89'。

unicode才是真正意義上的字符串,對字節串str使用正確的字符編碼進行解碼后獲得,并且len(u'漢') == 1。

再來看看encode()和decode()兩個basestring的實例方法,理解了str和unicode的區別后,這兩個方法就不會再混淆了:

 

 
  1. # coding: UTF-8 
  2. u = u'漢' 
  3. print repr(u) # u'/u6c49' 
  4. s = u.encode('UTF-8'
  5. print repr(s) # '/xe6/xb1/x89' 
  6. u2 = s.decode('UTF-8'
  7. print repr(u2) # u'/u6c49' 
  8. # 對unicode進行解碼是錯誤的 
  9. # s2 = u.decode('UTF-8') 
  10. # 同樣,對str進行編碼也是錯誤的 
  11. # u2 = s.encode('UTF-8') 

需要注意的是,雖然對str調用encode()方法是錯誤的,但實際上Python不會拋出異常,而是返回另外一個相同內容但不同id的str;對unicode調用decode()方法也是這樣。很不理解為什么不把encode()和decode()分別放在unicode和str中而是都放在basestring中,但既然已經這樣了,我們就小心避免犯錯吧。

2.2. 字符編碼聲明

源代碼文件中,如果有用到非ASCII字符,則需要在文件頭部進行字符編碼的聲明,如下:

#-*- coding: UTF-8 -*-

實際上Python只檢查#、coding和編碼字符串,其他的字符都是為了美觀加上的。另外,Python中可用的字符編碼有很多,并且還有許多別名,還不區分大小寫,比如UTF-8可以寫成u8。參見http://docs.python.org/library/codecs.html#standard-encodings。

另外需要注意的是聲明的編碼必須與文件實際保存時用的編碼一致,否則很大幾率會出現代碼解析異?!,F在的IDE一般會自動處理這種情況,改變聲明后同時換成聲明的編碼保存,但文本編輯器控們需要小心 :)

2.3. 讀寫文件

內置的open()方法打開文件時,read()讀取的是str,讀取后需要使用正確的編碼格式進行decode()。write()寫入時,如果參數是unicode,則需要使用你希望寫入的編碼進行encode(),如果是其他編碼格式的str,則需要先用該str的編碼進行decode(),轉成unicode后再使用寫入的編碼進行encode()。如果直接將unicode作為參數傳入write()方法,Python將先使用源代碼文件聲明的字符編碼進行編碼然后寫入。

 

 
  1. # coding: UTF-8 
  2. f = open('test.txt'
  3. s = f.read() 
  4. f.close() 
  5. print type(s) # <type 'str'
  6. # 已知是GBK編碼,解碼成unicode 
  7. u = s.decode('GBK'
  8. f = open('test.txt''w'
  9. # 編碼成UTF-8編碼的str 
  10. s = u.encode('UTF-8'
  11. f.write(s) 
  12. f.close() 

另外,模塊codecs提供了一個open()方法,可以指定一個編碼打開文件,使用這個方法打開的文件讀取返回的將是unicode。寫入時,如果參數是unicode,則使用open()時指定的編碼進行編碼后寫入;如果是str,則先根據源代碼文件聲明的字符編碼,解碼成unicode后再進行前述操作。相對內置的open()來說,這個方法比較不容易在編碼上出現問題。

 

 
  1. # coding: GBK 
  2. import codecs 
  3. f = codecs.open('test.txt', encoding='UTF-8'
  4. u = f.read() 
  5. f.close() 
  6. print type(u) # <type 'unicode'
  7. f = codecs.open('test.txt''a', encoding='UTF-8'
  8. # 寫入unicode 
  9. f.write(u) 
  10. # 寫入str,自動進行解碼編碼操作 
  11. # GBK編碼的str 
  12. s = '漢' 
  13. print repr(s) # '/xba/xba' 
  14. # 這里會先將GBK編碼的str解碼為unicode再編碼為UTF-8寫入 
  15. f.write(s)  
  16. f.close() 

2.4. 與編碼相關的方法

sys/locale模塊中提供了一些獲取當前環境下的默認編碼的方法。

 

 
  1. # coding:gbk 
  2. import sys 
  3. import locale 
  4. def p(f): 
  5. print '%s.%s(): %s' % (f.__module__, f.__name__, f()) 
  6. # 返回當前系統所使用的默認字符編碼 
  7. p(sys.getdefaultencoding) 
  8. # 返回用于轉換Unicode文件名至系統文件名所使用的編碼 
  9. p(sys.getfilesystemencoding) 
  10. # 獲取默認的區域設置并返回元祖(語言, 編碼) 
  11. p(locale.getdefaultlocale) 
  12. # 返回用戶設定的文本數據編碼 
  13. # 文檔提到this function only returns a guess 
  14. p(locale.getpreferredencoding) 
  15. # /xba/xba是'漢'的GBK編碼 
  16. # mbcs是不推薦使用的編碼,這里僅作測試表明為什么不應該用 
  17. print r"'/xba/xba'.decode('mbcs'):", repr('/xba/xba'.decode('mbcs')) 
  18. #在筆者的Windows上的結果(區域設置為中文(簡體, 中國)) 
  19. #sys.getdefaultencoding(): gbk 
  20. #sys.getfilesystemencoding(): mbcs 
  21. #locale.getdefaultlocale(): ('zh_CN', 'cp936') 
  22. #locale.getpreferredencoding(): cp936 
  23. #'/xba/xba'.decode('mbcs'): u'/u6c49' 

3.一些建議

3.1. 使用字符編碼聲明,并且同一工程中的所有源代碼文件使用相同的字符編碼聲明。

這點是一定要做到的。

3.2. 拋棄str,全部使用unicode。

按引號前先按一下u最初做起來確實很不習慣而且經常會忘記再跑回去補,但如果這么做可以減少90%的編碼問題。如果編碼困擾不嚴重,可以不參考此條。

3.3. 使用codecs.open()替代內置的open()。

如果編碼困擾不嚴重,可以不參考此條。

3.4. 絕對需要避免使用的字符編碼:MBCS/DBCS和UTF-16。

這里說的MBCS不是指GBK什么的都不能用,而是不要使用Python里名為'MBCS'的編碼,除非程序完全不移植。

Python中編碼'MBCS'與'DBCS'是同義詞,指當前Windows環境中MBCS指代的編碼。Linux的Python實現中沒有這種編碼,所以一旦移植到Linux一定會出現異常!另外,只要設定的Windows系統區域不同,MBCS指代的編碼也是不一樣的。分別設定不同的區域運行2.4小節中的代碼的結果:

 

 
  1. #中文(簡體, 中國) 
  2. #sys.getdefaultencoding(): gbk 
  3. #sys.getfilesystemencoding(): mbcs 
  4. #locale.getdefaultlocale(): ('zh_CN', 'cp936') 
  5. #locale.getpreferredencoding(): cp936 
  6. #'/xba/xba'.decode('mbcs'): u'/u6c49' 
  7. #英語(美國) 
  8. #sys.getdefaultencoding(): UTF-8 
  9. #sys.getfilesystemencoding(): mbcs 
  10. #locale.getdefaultlocale(): ('zh_CN', 'cp1252') 
  11. #locale.getpreferredencoding(): cp1252 
  12. #'/xba/xba'.decode('mbcs'): u'/xba/xba' 
  13. #德語(德國) 
  14. #sys.getdefaultencoding(): gbk 
  15. #sys.getfilesystemencoding(): mbcs 
  16. #locale.getdefaultlocale(): ('zh_CN', 'cp1252') 
  17. #locale.getpreferredencoding(): cp1252 
  18. #'/xba/xba'.decode('mbcs'): u'/xba/xba' 
  19. #日語(日本) 
  20. #sys.getdefaultencoding(): gbk 
  21. #sys.getfilesystemencoding(): mbcs 
  22. #locale.getdefaultlocale(): ('zh_CN', 'cp932') 
  23. #locale.getpreferredencoding(): cp932 
  24. #'/xba/xba'.decode('mbcs'): u'/uff7a/uff7a' 

可見,更改區域后,使用mbcs解碼得到了不正確的結果,所以,當我們需要使用'GBK'時,應該直接寫'GBK',不要寫成'MBCS'。

UTF-16同理,雖然絕大多數操作系統中'UTF-16'是'UTF-16-LE'的同義詞,但直接寫'UTF-16-LE'只是多寫3個字符而已,而萬一某個操作系統中'UTF-16'變成了'UTF-16-BE'的同義詞,就會有錯誤的結果。實際上,UTF-16用的相當少,但用到的時候還是需要注意。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
久久久99久久精品女同性| 欧洲成人午夜免费大片| 日韩中文字幕视频在线观看| 欧美日韩精品国产| 国产区精品在线观看| 欧美激情va永久在线播放| 91久久夜色精品国产网站| 久久久久久久网站| 色偷偷av一区二区三区乱| 91亚洲精品久久久| 久久综合88中文色鬼| 亚洲成avwww人| 亚洲精品国产精品自产a区红杏吧| 超碰精品一区二区三区乱码| 国产91九色视频| 日韩精品视频免费在线观看| 亚洲美女动态图120秒| 国产精品网站大全| 久久男人的天堂| 日本精品久久久久影院| 色伦专区97中文字幕| 日韩免费在线电影| 国产成人精品优优av| 久久免费国产视频| 国产精品第七影院| 中文字幕亚洲综合久久筱田步美| 成人看片人aa| 成人久久久久久久| 久久久久久美女| 亚洲精品日韩激情在线电影| 亚洲欧美激情视频| 亚洲欧美另类中文字幕| 久久精品人人爽| 大胆欧美人体视频| 精品毛片三在线观看| 亚洲欧洲午夜一线一品| 免费不卡欧美自拍视频| 国产69精品久久久| 国语自产偷拍精品视频偷| 欧美激情视频网址| 欧美激情一区二区三级高清视频| 欧美一区二区三区精品电影| 精品人伦一区二区三区蜜桃网站| 国产日韩欧美91| 国产精品免费一区二区三区都可以| 欧美—级高清免费播放| 久久久久国产精品免费网站| 精品久久久久久久久久久久久久| 成人黄色短视频在线观看| 97香蕉久久超级碰碰高清版| 日韩久久免费电影| 久久天天躁夜夜躁狠狠躁2022| www.日韩.com| 在线观看国产欧美| 欧美激情中文字幕乱码免费| 成人免费福利视频| 欧美网站在线观看| 亚洲欧美视频在线| 中文字幕欧美日韩在线| 中文字幕久久久av一区| 日韩中文在线中文网在线观看| 国产精品亚洲激情| 国产91成人在在线播放| 亚洲欧洲自拍偷拍| 国产成人精品日本亚洲| 国产精品aaaa| 久久久日本电影| 九九久久久久久久久激情| 一本色道久久88精品综合| 精品国偷自产在线视频99| 亚洲日韩中文字幕在线播放| 成人免费直播live| 亚洲国产成人av在线| 色综合色综合网色综合| 日日骚久久av| 国产欧美精品xxxx另类| 国产精品视频内| 欧美xxxx做受欧美.88| 91理论片午午论夜理片久久| 色播久久人人爽人人爽人人片视av| 欧美激情第99页| 欧美激情精品久久久久久| 97在线观看免费高清| 国产香蕉精品视频一区二区三区| 成人免费淫片aa视频免费| 久久影视电视剧免费网站| 中文字幕在线日韩| 最新的欧美黄色| 久久视频精品在线| 亚洲欧美精品中文字幕在线| 欧美日韩国产中文字幕| 青青青国产精品一区二区| 亚洲iv一区二区三区| 在线观看成人黄色| 日韩有码在线观看| 91九色国产社区在线观看| 国产精品v片在线观看不卡| 成人黄色免费在线观看| 欧美性xxxx极品hd满灌| 欧美午夜片欧美片在线观看| 国产丝袜一区二区三区免费视频| 欧美乱大交做爰xxxⅹ性3| 好吊成人免视频| 色综合男人天堂| 久久久之久亚州精品露出| 日韩在线欧美在线国产在线| 欧美在线视频在线播放完整版免费观看| 久久中文字幕在线视频| 98精品国产自产在线观看| 96国产粉嫩美女| 成人免费视频a| 久久视频在线免费观看| 国内精品久久久久久影视8| 国产成人免费av| 日韩av免费看| 欧美精品亚州精品| 91精品国产自产在线老师啪| 欧美老妇交乱视频| 国产精品中文字幕在线观看| 亚洲精品电影在线| 97久久伊人激情网| 国产一区二区免费| 中文字幕欧美亚洲| 日韩欧美在线网址| 欧美一级成年大片在线观看| 亚洲精品在线观看www| 高清一区二区三区日本久| 日韩av在线网站| 欧美精品在线网站| 亚洲国产精品va在线看黑人动漫| 青草青草久热精品视频在线观看| 亚洲一区二区三区香蕉| 最好看的2019的中文字幕视频| 日韩av网站导航| 国产精品久久久久不卡| 97人人爽人人喊人人模波多| 日韩精品免费综合视频在线播放| 亚洲综合精品一区二区| 欧美一级高清免费播放| 亚洲黄色在线看| 久久国产精品久久久久久久久久| 久久中文字幕一区| 美女福利视频一区| 日本精品一区二区三区在线| 亚洲精品v欧美精品v日韩精品| 欧美伦理91i| 欧美肥老太性生活视频| 欧美高清理论片| 欧美日韩国产va另类| 国产精品视频白浆免费视频| 亚洲国产精品成人av| 久久欧美在线电影| 亚洲肉体裸体xxxx137| 亚洲成人久久网| 91中文字幕一区| 九九九热精品免费视频观看网站| 欧美一级免费视频| 国产视频精品在线| 国产69久久精品成人看| 国产a∨精品一区二区三区不卡| 欧美国产日本高清在线| 在线丨暗呦小u女国产精品| 亚洲另类图片色| 亚洲精品xxxx|