編碼問題
字符編碼的發展
ASCII碼
ASCII碼即爲(American Standard Code for Information Interchange)由美國人發明,用於計算機進行字符處理和表示,使用7位(bit)來表示一個字符,總共可以表示128種字符。後來IBM對這套ASCII碼進行了擴充,使用8位來表示一個字符,新增了128種字符,這也僅僅是對一些拉丁字母和特殊符號的擴充。
GB2312碼
當計算機普及到全世界時,各個國家都針對本身國家的語言制定本身國家的編碼規範,我國就提出裏一套針對中文的GB2312的編碼方式,兼容ASCII碼,漢字用兩個字節表示,英文和符號用一個字節的ASCII表示。ASCII碼最高位爲0,當機器度到字節最高位爲0的時候,讀爲ASCII碼,GB2312碼漢字區的兩個字節的最高位都爲1
GBK碼
GB2312只能編入部分經常使用漢字,爲了把更多的漢字編入進來,針對GB2312進行擴充,就創造出了GBK標準。GBK碼用兩個字節表示漢字(當高字節首位爲1時就表示漢字的開始),一個字節表示英文和符號,兼容ASCII碼和GB2312碼。其編碼範圍從8140至FEFE(剔除xx7F),共23940個碼位,共收錄了21003個漢字。其中GB2312碼部分,兩個字節的最高位都爲1以此斷定是GB2312碼,GBK碼的高字節首位爲大於1(棄用擴展ASCII碼128-255)。
ANSI
相似我國的編碼方案,其餘地區和國家也制定了本身的編碼方案,如日本的Shift-JIS等等。這些編碼方案稱爲 「DBCS」(Double Byte Charecter Set 雙字節字符集)」便是用雙字節表示一個字符,也稱爲ANSI,這裏的ANSI表明了不一樣國家的不一樣編碼方案。在簡體中文Windows操做系統中,ANSI 編碼表明 GBK 編碼;在繁體中文Windows操做系統中,ANSI編碼表明Big5;在日文Windows操做系統中,ANSI 編碼表明 Shift_JIS 編碼。因爲ANSI的定義,也引起了一個嚴重的問題:不一樣 ANSI 編碼之間互不兼容,當信息在國際間交流時,沒法將屬於兩種語言的文字,存儲在同一段 ANSI 編碼的文本中。
UNICODE字符集
爲了統一全世界的文字編碼,ISO(國際標準化組織)制定了UNICODE字符集(Universal Multiple-Octet Coded Character Set)UNICODE-2碼用兩個字節編碼,UNICODE-4碼用四個字節編碼。因爲ASCII碼錶示一個字符1個字節,而Unicode須要2,會大量浪費內存,而且個嚴格意義上說Unicode只是一套標準,爲全世界文字給予一個惟一的編碼,可是並無規定在計算機中如何存儲,因此根據Unicode標準來制定具體的實施方案就是UTF-8。
UTF-8碼
UTF-8是可變長編碼根據具體狀況用1-4個字節來編碼,英文用本來的ASCII碼,歐洲語系2個字節,東亞三個字節,其餘及特殊字符用4個
計算機硬盤等存儲的是utf-8節省存儲空間,計算機內存存儲的是Unicode,所以讀寫的時候會出現編碼轉換;網絡傳輸同樣,網絡傳輸使用utf-8編碼節省通訊開銷,計算機內存中存儲的是Unicode,所以讀寫的時候也會出現編碼轉換。
如何查看文件編碼
將文件用記事本打開,而後另存爲界面就能看到html
運行程序時各編碼間的聯繫
-
文件編碼:文件以何種編碼存入硬盤,以何種編碼讀取出來。
-
系統編碼:操做系統是何默認編碼,意味着系統軟件的默認編碼都是操做系統的默認編碼。例如簡體中文windows默認編碼爲GBK,繁體中文windows默認編碼爲Big5碼,Linux默認編碼爲UTF-8。
-
編輯器編碼:因爲硬盤讀寫速度太慢編輯器直接與內存交互,在編輯器編寫的內容也是存放於內存中的,斷電後數據丟失,於是要保存到硬盤上。保存後,從內存中把數據刷到了硬盤上。編輯器,如word,pycharm等,有默認的編碼,在此編輯器編寫文件會按該編輯器默認編碼方式存入硬盤(特殊聲明除外)
-
解釋器編碼:啓動解釋器第一步至關於先啓動了一個編輯器,經過編輯器先將文件讀到內存中,而後進行解析。編碼方面,以cpython解釋器爲例,首以解析器的編碼去解析文件。
運行程序時各編碼間的聯繫
下面以一個例子來講明程序運行時用到的編碼
以python3和簡體中文windows環境爲例:
-
在pycharm中編寫hello.py文件,而後保存(文件以utf-8編碼保存在硬盤中)。
# hello.py
s='韋連鑫'
print('hello' + s)
-
關閉後打開,pycharm以utf-8的編輯器默認編碼解析硬盤中文件的二進制數據,轉成unicode存入內存,以明文的形式顯示給咱們看。
-
執行,Cpython解釋器先調用編輯器以utf-8的編輯器默認編碼解碼文件bytes數據爲unicode,而後翻譯成c代碼,轉化成二進制後調用cpu進行執行。
python版本對編碼的影響
python2中的編碼
在py2中,有兩種字符串類型:str類型和unicode類型。str和unicode分別存的是字節(Bytes)數據和unicode數據。str 和 unicode 都有 encode 和 decode 方法。可是不建議對 str 使用 encode,對 unicode 使用 decode, 這是 Python2 設計上的缺陷。Python3 則進行了優化,str 只有一個 encode 方法將字符串轉化爲一個字節碼,並且 bytes 也只有一個 decode 方法將字節碼轉化爲一個文本字符串。
#_*_coding:gbk_*_
#!/usr/bin/env python
x='林'
# print x.encode('gbk') #報錯
print x.decode('gbk') #結果:林
s = " " # 類型是str,它是依操做系統而定的某種編碼類型的字符串
s = u" " # 類型是unicode,Unicode編碼類型的字符串
python3中的編碼
python3把字符串變成了unicode,文件默認編碼變成了utf-8,這意味着,只要用python3,不管你的程序是以哪一種編碼開發的,都不用擔憂中文問題。
python3除了把字符串的編碼改爲了unicode, 還把str 和bytes 作了明確區分, str 就是unicode格式的字符,bytes就是單純二進制,兩者經過encode和decode進行轉換。
s = '你好' # unicode類型
print(s) # 你好
print(s.encode('gbk')) # b'\xc4\xe3\xba\xc3'
ss = s.encode('gbk') # unicode轉換成bytes
print(ss.decode('gbk')) # 你好
Python3 bytes 函數
Python3 內置函數bytes()
描述
bytes 函數返回一個新的 bytes 對象,該對象是一個 0 <= x < 256 區間內的整數不可變序列。它是 bytearray 的不可變版本。
語法
如下是 bytes 的語法:
class bytes([source[, encoding[, errors]]])
>>>a = bytes([1,2,3,4])
>>> a
b'\x01\x02\x03\x04'
>>> type(a)
<class 'bytes'>
>>>
>>> a = bytes('hello','ascii')
>>>
>>> a
b'hello'
>>> type(a)
<class 'bytes'>
>>>
版本對對編碼的影響
-
Python2 的 str 和 unicode 都是 basestring 的子類,因此二者能夠直接進行拼接操做。而 Python3 中的 bytes 和 str 是兩個獨立的類型,二者不能進行拼接。
-
Python2 中,普通的,用引號括起來的字符,就是 str,str前面加個字母u的就是unicode;此時str字符串的編碼類型,對應着你的 Python 文件自己保存爲什麼種編碼有關,最多見的 Windows 平臺中,默認用的是 GBK。Python3 中,被單引號或雙引號括起來的字符串,就已是 Unicode 類型的 str 了。
對編碼理解的檢驗
若是你看懂了上面的編碼問題,下面這幾種狀況能夠檢驗是否真正理解
-
cmd下的亂碼問題
這裏有一個hello.py文件
#coding:utf8
print ('hello 張三')
件保存時的編碼也爲utf8。
問題:爲何在IDE下用2或3執行都沒問題,在cmd.exe下3正確,2亂碼呢?
答案:咱們在win下的終端即cmd.exe去執行,你們注意,cmd.exe自己也一個軟件;當咱們python2 hello.py時,python2解釋器(默認ASCII編碼)去按聲明的utf8編碼文件,而文件又是utf8保存的,因此沒問題;問題出在當咱們print’苑昊’時,解釋器這邊正常執行,也不會報錯,只是print的內容會傳遞給cmd.exe用來顯示,而在py2裏這個內容就是utf8編碼的字節數據,可這個軟件默認的編碼解碼方式是GBK,因此cmd.exe用GBK的解碼方式去解碼utf8天然會亂碼。
py3正確的緣由是傳遞給cmd的是unicode數據,cmd.exe能夠識別內容,因此顯示沒問題。
-
open()中的編碼問題
建立一個hello文本,保存成utf8:
同目錄下建立一個index.py
f=open('hello')
print(f.read())
爲何在linux下,結果正常,在win下倒是亂碼(py3解釋器)?
由於你的win的操做系統安裝時是默認的gbk編碼,而linux操做系統默認的是utf8編碼;
當執行open函數時,調用的是操做系統打開文件,操做系統用默認的gbk編碼去解碼utf8的文件,天然亂碼。
解決辦法:
f=open('hello',encoding='utf8')
print(f.read())
若是你的文件保存的是gbk編碼,在win 下就不用指定encoding了。
另外,若是你的win上不須要指定給操做系統encoding=’utf8’,那就是你安裝時就是默認的utf8編碼或者已經經過命令修改爲了utf8編碼。
注意:open這個函數在py2裏和py3中是不一樣的,py3中有了一個encoding=None參數。
-
文件亂碼與運行報錯緣由
以最開始的hello文件爲例,新建一個hello.py文件並以gbk編碼保存
# hello.py
s='韋連鑫'
print('hello' + s)
在pycharm中打開後以下
因爲pacharm默認編碼是utf-8,因此在解碼文件時把GBK文件以UTF-8讀出,因此會顯示亂碼,此處能夠經過pycharm右下角的編碼格式更改,成gbk則可正常顯示。
當文件運行時,又會報出以下錯誤
緣由是python3解析器默認編碼是utf-8,以utf-8解碼gbk文件因此會報以下錯誤
解決方法:
在文件開頭加上# encoding=gbk
如此,解釋器與編輯器都會以gbk方式來讀取和解碼文件
總結
注意
- python文件頭部聲明的編碼和pycharm右下角的編碼(文件默認編碼)意思是文件都是按聲明編碼存入硬盤的(py2默認爲ASCII碼py2默認爲utf-8),
讀文件按文件頭部聲明(無聲明默認爲utf-8)讀到pycharm,右下角編碼方式能夠用reload選取讀取文件的編碼方式(不改變原文件存儲的編碼),可是右下角的編碼明明是存入的編碼方式,你這樣一改右下角編碼方式不就和文件的存儲編碼方式不同了麼。別急,只要你保存了文件,該文件就又按右下角的編碼方式保存到了磁盤,這樣讀取方式和保存方式就又同樣了python
- py3會自動將編碼轉換成UNICODE放入內存,以下。
- py2中有str和UNICODE兩種字符串類型,不是UNICODE的都是str
- Python2中默認編碼爲ASCII碼,想寫中文就必須在開頭加上聲明,例如你文件編碼是UTF-8,存到內存仍是UTF-8,這樣在windows中是亂碼,由於windows中內碼是gbk碼,須要用encode和decode
python3默認編碼爲UNICODE碼,會自動轉換,不存在這些問題linux
PY3 除了把字符串的編碼改爲了unicode, 還把str 和bytes 作了明確區分, str 就是unicode格式的字符, bytes就是單純二進制啦。windows
在看實際代碼的例子前,咱們來聊聊,python3 執行代碼的過程網絡
1.解釋器找到代碼文件,把代碼字符串按文件頭定義的編碼加載到內存,轉成unicode編輯器
2.把代碼字符串按照語法規則進行解釋,函數
3.全部的變量字符都會以unicode編碼聲明優化
更更詳細的解釋:http://www.javashuo.com/article/p-aihpvyuo-c.html編碼