您好,登錄后才能下訂單哦!
這篇文章主要講解了“Python中的編碼問題有哪些”,文中的講解內(nèi)容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“Python中的編碼問題有哪些”吧!
每個做 JavaWeb 開發(fā)的新手都會遇到亂碼問題,每個做 Python 爬蟲的新手都會遇到編碼問題,為什么編碼問題那么蛋疼呢?這個問題要從1992年 Guido van Rossum 創(chuàng)造 Python 這門語言說起,那時的 Guido 絕對沒想到的是 Python 這門語言在今天會如此受大家歡迎,也不會想到計算機發(fā)展速度會如此驚人,盡管 Guido 在當初設計這門語言時是不需要關心編碼的,因為在英語世界里,字符的個數(shù)非常有限,26個字母(大小寫)、10個數(shù)字、標點符號、控制符,也就是鍵盤上所有的鍵所對應的字符加起來也不過是一百多個字符而已,這在計算機中用一個字節(jié)的存儲空間來表示一個字符是綽綽有余的,因為一個字節(jié)相當于8個比特位,8個比特位可以表示256個符號。于是聰明的美國人就制定了一套字符編碼的標準叫ASCII(American Standard Code for Information Interchange),每個字符都對應唯一的一個數(shù)字,比如字符A
對應的二進制數(shù)值是01000001
,對應的十進制就是65。最開始ASCII只定義了128個字符編碼,包括96個文字和32個控制符號,一共128個字符只需要一個字節(jié)的7位就能表示所有的字符,因此 ASCII 只使用了一個字節(jié)的后7位,最高位都為0。每個字符與ASCII碼的對應關系可查看網(wǎng)站ascii-code。
然而計算機慢慢地普及到其他西歐地區(qū)時,他們發(fā)現(xiàn)還有很多西歐所特有的字符是 ASCII 編碼表中沒有的,于是后來出現(xiàn)了可擴展的 ASCII 叫 EASCII ,顧名思義,它是在ASCII的基礎上擴展而來,把原來的7位擴充到8位,它完全兼容ASCII,擴展出來的符號包括表格符號、計算符號、希臘字母和特殊的拉丁符號。然而 EASCII 時代是一個混亂的時代,大家沒有統(tǒng)一標準,他們各自把最高位按照自己的標準實現(xiàn)了自己的一套字符編碼標準,比較著名的就有 CP437, CP437 是 Windows 系統(tǒng)中使用的字符編碼,如下圖:
另外一種被廣泛使用的 EASCII 還有 ISO/8859-1(Latin-1),它是國際標準化組織(ISO)及國際電工委員會(IEC)聯(lián)合制定的一系列8位元字符集的標準,ISO/8859-1 只繼承了 CP437 字符編碼的128-159之間的字符,所以它是從160開始定義的,不幸的是這些眾多的 ASCII 擴充字集之間互不兼容。
GBK
隨著時代的進步,計算機開始普及到千家萬戶,比爾蓋茨讓每個人桌面都有一臺電腦的夢想得以實現(xiàn)。但是計算機進入中國不得不面臨的一個問題就是字符編碼,雖然咱們國家的漢字是人類使用頻率最多的文字,漢字博大精深,常見的漢字就有成千上萬,這已經(jīng)大大超出了 ASCII 編碼所能表示的字符范圍了,即使是 EASCII 也顯得杯水車薪,于是聰明的中國人自己弄了一套編碼叫 GB2312,又稱GB0,1981由中國國家標準總局發(fā)布。GB2312 編碼共收錄了6763個漢字,同時他還兼容 ASCII,GB 2312的出現(xiàn),基本滿足了漢字的計算機處理需要,它所收錄的漢字已經(jīng)覆蓋中國大陸99.75%的使用頻率,不過 GB2312 還是不能100%滿足中國漢字的需求,對一些罕見的字和繁體字 GB2312 沒法處理,后來就在GB2312的基礎上創(chuàng)建了一種叫 GBK 的編碼,GBK 不僅收錄了27484個漢字,同時還收錄了藏文、蒙文、維吾爾文等主要的少數(shù)民族文字。同樣 GBK 也是兼容 ASCII 編碼的,對于英文字符用1個字節(jié)來表示,漢字用兩個字節(jié)來標識。
對于如何處理中國人自己的文字我們可以另立山頭,按照我們自己的需求制定一套編碼規(guī)范,但是計算機不止是美國人和中國人用啊,還有歐洲、亞洲其他國家的文字諸如日文、韓文全世界各地的文字加起來估計也有好幾十萬,這已經(jīng)大大超出了ASCII碼甚至GBK所能表示的范圍了,況且人家為什么用采用你GBK標準呢?如此龐大的字符庫究竟用什么方式來表示好呢?于是統(tǒng)一聯(lián)盟國際組織提出了Unicode編碼,Unicode的學名是”Universal Multiple-Octet Coded Character Set”,簡稱為UCS。Unicode有兩種格式:UCS-2和UCS-4。UCS-2就是用兩個字節(jié)編碼,一共16個比特位,這樣理論上最多可以表示65536個字符,不過要表示全世界所有的字符顯示65536個數(shù)字還遠遠不過,因為光漢字就有近10萬個,因此Unicode4.0規(guī)范定義了一組附加的字符編碼,UCS-4就是用4個字節(jié)(實際上只用了31位,最高位必須為0)。理論上完全可以涵蓋一切語言所用的符號。世界上任何一個字符都可以用一個Unicode編碼來表示,一旦字符的Unicode編碼確定下來后,就不會再改變了。但是Unicode有一定的局限性,一個Unicode字符在網(wǎng)絡上傳輸或者最終存儲起來的時候,并不見得每個字符都需要兩個字節(jié),比如一字符“A“,用一個字節(jié)就可以表示的字符,偏偏還要用兩個字節(jié),顯然太浪費空間了。第二問題是,一個Unicode字符保存到計算機里面時就是一串01數(shù)字,那么計算機怎么知道一個2字節(jié)的Unicode字符是表示一個2字節(jié)的字符呢,還是表示兩個1字節(jié)的字符呢,如果你不事先告訴計算機,那么計算機也會懵逼了。Unicode只是規(guī)定如何編碼,并沒有規(guī)定如何傳輸、保存這個編碼。例如“漢”字的Unicode編碼是6C49,我可以用4個ascii數(shù)字來傳輸、保存這個編碼;也可以用utf-8編碼的3個連續(xù)的字節(jié)E6 B1 89來表示它。關鍵在于通信雙方都要認可。因此Unicode編碼有不同的實現(xiàn)方式,比如:UTF-8、UTF-16等等。這里的Unicode就像英語一樣,做為國與國之間交流世界通用的標準,每個國家有自己的語言,他們把標準的英文文檔翻譯成自己國家的文字,這是實現(xiàn)方式,就像utf-8。
UTF-8(Unicode Transformation Format)作為Unicode的一種實現(xiàn)方式,廣泛應用于互聯(lián)網(wǎng),它是一種變長的字符編碼,可以根據(jù)具體情況用1-4個字節(jié)來表示一個字符。比如英文字符這些原本就可以用ASCII碼表示的字符用UTF-8表示時就只需要一個字節(jié)的空間,和ASCII是一樣的。對于多字節(jié)(n個字節(jié))的字符,第一個字節(jié)的前n為都設為1,第n+1位設為0,后面字節(jié)的前兩位都設為10。剩下的二進制位全部用該字符的unicode碼填充。
以漢字“好”為例,“好”對應的Unicode是597D,對應的區(qū)間是0000 0800—0000 FFFF,因此它用UTF-8表示時需要用3個字節(jié)來存儲,597D用二進制表示是: 0101100101111101,填充到1110xxxx 10xxxxxx 10xxxxxx得到11100101 10100101 10111101,轉(zhuǎn)換成16進制:e5a5bd,因此“好”的Unicode”597D”對應的UTF-8編碼是”E5A5BD”
中文 好 unicode 0101 100101 111101 編碼規(guī)則 1110xxxx 10xxxxxx 10xxxxxx -------------------------- utf-8 11100101 10100101 10111101 -------------------------- 16進制utf-8 e 5 a 5 b d
現(xiàn)在總算把理論說完了。再來說說Python中的編碼問題。Python的誕生時間比Unicode要早很多,Python的默認編碼是ASCII
>>> import sys >>> sys.getdefaultencoding() 'ascii'
所以在Python源代碼文件中如果不顯示地指定編碼的話,將出現(xiàn)語法錯誤
#test.py print "你好"
上面是test.py腳本,運行 python test.py 就會包如下錯誤:
File “test.py”, line 1
yntaxError: Non-ASCII character ‘\xe4′ in file test.py on line 1, but no encoding declared; see http://www.python.org/
ps/pep-0263.html for details
為了在源代碼中支持非ASCII字符,必須在源文件的第一行或者第二行顯示地指定編碼格式:
# coding=utf-8
或者是:
#!/usr/bin/python # -*- coding: utf-8 -*-
在python中和字符串相關的數(shù)據(jù)類型,分別是str、unicode兩種,他們都是basestring的子類,可見str與unicode是兩種不同類型的字符串對象。
basestring / \ / \ str unicode
對于同一個漢字“好”,用str表示時,它對應的就是utf-8編碼的’\xe5\xa5\xbd’,而用unicode表示時,他對應的符號就是u’\u597d’,與u"好"
是等同的。需要補充一點的是,str類型的字符其具體的編碼格式是UTF-8還是GBK,還是其他格式,根據(jù)操作系統(tǒng)相關。比如在Windows系統(tǒng)中,cmd命令行中顯示的:
# windows終端 >>> a = '好' >>> type(a) <type 'str'> >>> a '\xba\xc3'
而在Linux系統(tǒng)的命令行中顯示的是:
# linux終端 >>> a='好' >>> type(a) <type 'str'> >>> a '\xe5\xa5\xbd' >>> b=u'好' >>> type(b) <type 'unicode'> >>> b u'\u597d'
不論是Python3x、Java還是其他編程語言,Unicode編碼都成為語言的默認編碼格式,而數(shù)據(jù)最后保存到介質(zhì)中的時候,不同的介質(zhì)可有用不同的方式,有些人喜歡用UTF-8,有些人喜歡用GBK,這都無所謂,只要平臺統(tǒng)一的編碼規(guī)范,具體怎么實現(xiàn)并不關心。
那么在Python中str和unicode之間是如何轉(zhuǎn)換的呢?這兩種類型的字符串類型之間的轉(zhuǎn)換就是靠這兩個方法decode
和encode
。
#從str類型轉(zhuǎn)換到unicode s.decode(encoding) =====> <type 'str'> to <type 'unicode'> #從unicode轉(zhuǎn)換到str u.encode(encoding) =====> <type 'unicode'> to <type 'str'> >>> c = b.encode('utf-8') >>> type(c) <type 'str'> >>> c '\xe5\xa5\xbd' >>> d = c.decode('utf-8') >>> type(d) <type 'unicode'> >>> d u'\u597d'
這個’\xe5\xa5\xbd’就是unicode u’好’通過函數(shù)encode編碼得到的UTF-8編碼的str類型的字符串。反之亦然,str類型的c通過函數(shù)decode解碼成unicode字符串d。
str(s)和unicode(s)是兩個工廠方法,分別返回str字符串對象和unicode字符串對象,str(s)是s.encode(‘a(chǎn)scii’)的簡寫。實驗:
>>> s3 = u"你好" >>> s3 u'\u4f60\u597d' >>> str(s3) Traceback (most recent call last): File "<stdin>", line 1, in <module> UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)
上面s3是unicode類型的字符串,str(s3)相當于是執(zhí)行s3.encode(‘a(chǎn)scii’)因為“你好”兩個漢字不能用ascii碼來表示,所以就報錯了,指定正確的編碼:s3.encode(‘gbk’)或者s3.encode(“utf-8”)就不會出現(xiàn)這個問題了。類似的unicode有同樣的錯誤:
>>> s4 = "你好" >>> unicode(s4) Traceback (most recent call last): File "<stdin>", line 1, in <module> UnicodeDecodeError: 'ascii' codec can't decode byte 0xc4 in position 0: ordinal not in range(128) >>>
unicode(s4)等效于s4.decode(‘a(chǎn)scii’),因此要正確的轉(zhuǎn)換就要正確指定其編碼s4.decode(‘gbk’)或者s4.decode(“utf-8”)。
所有出現(xiàn)亂碼的原因都可以歸結(jié)為字符經(jīng)過不同編碼解碼在編碼的過程中使用的編碼格式不一致,比如:
# encoding: utf-8 >>> a='好' >>> a '\xe5\xa5\xbd' >>> b=a.decode("utf-8") >>> b u'\u597d' >>> c=b.encode("gbk") >>> c '\xba\xc3' >>> print c ??
utf-8編碼的字符‘好’占用3個字節(jié),解碼成Unicode后,如果再用gbk來解碼后,只有2個字節(jié)的長度了,最后出現(xiàn)了亂碼的問題,因此防止亂碼的最好方式就是始終堅持使用同一種編碼格式對字符進行編碼和解碼操作。
對于如unicode形式的字符串(str類型):
s = 'id\u003d215903184\u0026index\u003d0\u0026st\u003d52\u0026sid’
轉(zhuǎn)換成真正的unicode需要使用:
s.decode('unicode-escape')
測試:
>>> s = 'id\u003d215903184\u0026index\u003d0\u0026st\u003d52\u0026sid\u003d95000\u0026i' >>> print(type(s)) <type 'str'> >>> s = s.decode('unicode-escape') >>> s u'id=215903184&index=0&st=52&sid=95000&i' >>> print(type(s)) <type 'unicode'> >>>
以上代碼和概念都是基于Python2.x。
感謝各位的閱讀,以上就是“Python中的編碼問題有哪些”的內(nèi)容了,經(jīng)過本文的學習后,相信大家對Python中的編碼問題有哪些這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內(nèi)容。