python字符編碼

字符編碼介紹

什麼是字符編碼

這裏的字符指的是 人類能識別的字符,字符方便記憶。在計算機中,都是按照二進制存儲,方便存儲的是數字,因此,字符在計算機中的存儲須要先轉換爲數字,而後再進行存儲。
存儲過程:字符 --> 數字,讀取過程:數字 --> 字符 ~
以上兩個轉換過程當中,字符和數字之間存在一個一一對應的關係,一個字符對應一個特定的數字,這個一一對應的關係就是所謂的字符編碼~python

字符編碼問題

計算機出現以後,美國人搞出了一套ASCII,以下圖。ASCII表中一個字符使用一個字節來表示,一個字節8位,最多隻能表示256個字符(2**8 = 256)。表中的字符包括英文、字母、數字,還有一些特殊字符,這些字符和數字 之間存在一一對應關係,例如:97表示小寫的a,65表示大寫的A...
python字符編碼windows

其實ASCII僅使用了一個字節中的7位來表示字符,一共127個字符(後128個稱爲擴展ASCII碼)。ASCII是美國人發明的,因此除了英文,不能用於其餘語言。因而中國人就指定了gb2312編碼,其中包含了中文在內的字符 --> 數字的對應關係,日本人也制定了 Shift_JIS 編碼,韓國人的 Euc-kr 編碼等等,各國的人都有本身的一套標準。網絡

這樣在使用過程當中,例如,一篇文檔中僅有一種語言,那麼 就不存在問題;可是若是這篇文檔中存在多種語言,那麼不論是用哪一種編碼標準,都會存在亂碼問題,這時候 unicode 就應運而生,unicode 可以兼容萬國字符,從而避免以上狀況出現的亂碼問題~ide

unicode介紹

unicode 經常使用2個字節(16位二進制)表明一個字符,生僻字須要用4個字節。unicode 兼容 ascii,例如:小寫字母x,用 ascii 表示是 0111 1000(二進制),使用 unicode 表示 爲 0000 0000 0111 1000(二進制),可見 二者的值一致,只是使用 unicode 表示使用了2個字節,而是用 ascii 表示僅使用了一個字節,存儲空間多了一倍~編碼

unicode 中存放了與其餘編碼的映射關係,因此 unicode 能夠兼容 萬國字符。"unicode 中存放了與其餘編碼的映射關係" 這句話是否是很差理解,簡單的說就是,unicode 編碼 能夠轉爲 其餘編碼,例如gbk、Shift_JIS等,其餘的編碼也能夠經過 unicode 中存在的映射關係 轉爲 unicode 編碼,轉換的規則以下圖:
python字符編碼code

經過以下示例來更進一步的解釋,這張圖表示 unicode 編碼 和 gbk 等其餘編碼的映射關係(unicode映射表,截取而來),中文 '人' 字的 unicode 編碼是 '4eba',對應的 gbk 編碼是 '484b'
python字符編碼orm

python3環境blog

>>> x = '\u4eba'                # unicode 碼
>>> x
'人'
>>> x.encode('gbk')         # 轉爲 gbk 編碼
b'\xc8\xcb'

>>> b'\xc8\xcb'.decode('gbk')    # gbk 編碼轉爲 unicode 碼
'人'

單引號或雙引號中以 \u 開頭的都是 unicode 碼,unicode 碼對每個字符用4位16進制數表示。具體規則是:將一個字符(char)的高8位與低8位分別取出,轉化爲16進制數, 若是轉化的16進制數的長度不足2位,則在其後補0,而後將高、低8位轉成的16進制字符串拼接起來並在前面補上 "\u" 。 ip

漢子 '中' 由 unicode 編碼轉爲 gbk 編碼後,顯示的 gbk 編碼爲 'c8cb',和圖中的 '484b' 便不符合,這是由於GBK 的編碼爲了兼容 ASCII,即若是是英文,就用一個字節表示,2個字節就是中文,若是1個字節的第一位(最左邊一位)是0表示是 ASCII,若是連續的2個字節的第一位都是1,那麼這2個字節表示爲一箇中文,因此這裏的 'c8cb' 去掉首位的1後,就是 '484B' ~內存

unicode 和 UTF-8

ASCII 使用一個字節表示一個字符,而 unicode 須要2個字節,這樣對於英文的文本而言,存儲空間就多了一倍,因而就有了 UTF-8(可變長存儲,Unicode Transformation Format),UTF-8 簡稱萬國碼,能夠統一顯示中文簡體繁體及其它語言(如英文,日文,韓文)。UTF-8 編碼中英文字符只使用1字節表示,中文字符用3字節,其餘生僻字使用更多的字節存儲~
 
在內存中的字符統一使用 unicode 編碼,這樣能夠避免亂碼問題,當數據須要存儲到硬盤或者在網絡之間進行傳遞時,再將 unicode 編碼轉爲 其餘編碼標準(如今大多數狀況都是UTF-8,也推薦使用UTF-8),由於這樣更節省空間,也能夠減少網絡的傳輸壓力。

當數據須要從新讀入內存,就須要經過解碼轉爲 unicode,以前使用何種方式編碼存放到磁盤,就須要使用同一種編碼標準進行解碼。大體過程以下(UTF-8):

unicode(內存) -----> encode 編碼 -------->utf-8(磁盤)
utf-8(磁盤) --------> decode 解碼 ---------->unicode(內存)

 
這樣也許有人會問,爲何內存中不直接使用 utf-8 編碼標準,utf-8 中囊括了全部語言,那是由於如今不少軟件還在使用各國的編碼標準(例如Shift_JIS,GBK,Euc-kr的等),utf-8 編碼標準中不存在 和這些編碼的映射關係(簡而言之就是 Shift_JIS,GBK,Euc-kr等這些編碼沒法轉換爲 utf-8編碼,utf-8編碼也不能轉換爲這些編碼),而 unicode 中存在,因此內存中一概使用 unicode 編碼標準能夠避免亂碼問題。utf-8 的出現主要是爲了減少存儲的空間,若是哪一天全部的軟件都是使用 utf-8 編碼標準,那數據讀取到內存中也不須要再轉爲 unicode。

常見的編碼問題

常見的編碼問題通常有2種:

--第一種狀況
在數據存儲時,編碼錯誤。示例以下,文本中既有中文又有韓語,可是在存儲時使用 Euc-kr 編碼標準
python字符編碼

保存後從新打開:
python字符編碼

出現如上狀況的問題在於,在使用Euc-kr 編碼存儲時就已經發生了錯誤,韓文使用 Euc-kr 編碼(unicode --> Euc-kr)沒有問題,可是中文這個過程沒法完成,致使編碼失敗,數據沒法恢復~

--第二種狀況
數據正確編碼後存儲,在讀取時使用了錯誤的編碼
文本中只有韓文,且使用 Euc-kr 編碼後保存
python字符編碼

從新 使用其餘編碼標準 解碼後打開
python字符編碼

出現了亂碼,文本編碼後存儲沒有問題,可是在打開文件時使用了錯誤的解碼方式。這裏只要調整解碼方式就能夠,不會致使數據丟失!
python字符編碼
從新設置成 Euc-kr 就能夠

總結:
一、內存中字符的存儲都是使用 unicode 編碼,在寫入到磁盤或者進行網絡傳輸時纔會將 unicode 編碼轉換成其餘編碼標準
二、在寫入到磁盤上或者進行網絡傳輸時,使用什麼編碼標準 進行編碼,以後就須要使用一樣的編碼標準進行解碼

三、推薦使用 utf-8 編碼標準,多國的文字能夠同時存在於一個文本中~
python字符編碼

python中的編碼

py文件的編碼

執行python程序,首先會啓動 python解釋器,而後 python解釋器會以 py文件 最前面2行指定的編碼方式來將py文件的內容讀入內存,定義編碼經常使用的方式以下:

1)# coding=<encoding name>
2)# -*- coding: <encoding name> -*-

如上語句必須放在py文件的第一行或者第二行~

若py文件中不指定編碼方式,則 python2 默認使用 ASCII,python3 默認使用 UTF-8。這個能夠經過sys.getdefaultencoding() 查看
python2環境

luyideMacBook-Pro:~ baby$ python
Python 2.7.10 (default, Oct  6 2017, 22:29:07) ...
>>> import sys
>>> sys.getdefaultencoding()
'ascii'

python3環境

C:\Users\Baby>python
Python 3.6.4 (v3.6.4:d48eceb, Dec 19 2017, 06:54:40)...
>>> import sys
>>> sys.getdefaultencoding()
'utf-8'

python解釋器加載代碼到內存後,代碼在內存中都是以 unicode 的格式存放的,可是當解釋器執行到存放字符串的語句時,例如:my_str = 'hello kitty',python解釋器會申請內存,而後將字符串編碼成 py文件開頭指定的編碼格式進行編碼,而後存放。python2中都是以上述過程存放字符串的;在python3中,字符串統一都是用 unicode 格式存放,python3中這樣作 避免了不少沒必要要的麻煩~~

python2中的str和unicode類型

--str類型
如上所說,python2中的字符串都是以 py文件開頭指定的編碼格式進行編碼後存放
python2環境

# -*- coding: utf-8 -*-

my_str = '你好'
print type(my_str)
print (my_str,)

輸出結果:
<type 'str'>
('\xe4\xbd\xa0\xe5\xa5\xbd',)

Tip:查看字符串在內存中存放的真實格式,能夠經過print元組或列表查看,直接print 會自動轉換編碼~

--unicode類型
python2環境

# -*- coding: utf-8 -*-

my_str = u'你好'
print type(my_str)
print (my_str,)

輸出結果:
<type 'unicode'>
(u'\u4f60\u597d',)

Tip:字符串前面加個u,即字符串保存爲 unicode 格式~

unicode字符串 可經過編碼,轉換爲其餘編碼格式保存

# -*- coding: utf-8 -*-

my_str = u'你好'
print (my_str.encode('utf-8'),)

輸出結果:
('\xe4\xbd\xa0\xe5\xa5\xbd',)

python3中的str和bytes類型

在python3中,python解釋器將字符串保存至新申請的內存上,默認使用的就是unicode。

x = '你好'                  # 默認就使用unicode保存到內存中,前面無需加 u
print(type(x))            # <class 'str'>

y = x.encode('utf-8')
print(y)                       # b'\xe4\xbd\xa0\xe5\xa5\xbd'
print(type(y))              # <class 'bytes'>

python3中申明 bytes 類型
x = bytes('abc'.encode('utf-8'))
y = b'abc'

print(type(x))        # <class 'bytes'>
print(type(y))        # <class 'bytes'>

Tip:
1)python3中的字符串默認就是以unicode形式保存,與python2中的 x = u'你好' 語句相似
2)python3中的字符串 x = '你好' 使用 utf-8 編碼後輸出的結果是 b'\xe4\xbd\xa0\xe5\xa5\xbd',這與python2中的 "my_str = '你好';print ((my_str,))" (# -- coding: utf-8 --)輸出結果一致。.....python2中的 str 類型就是 python3 中的 bytes 類型~

查看python2中的 bytes 源代碼:
python字符編碼

python2中的bytes是爲了兼容python3的寫法,python2 中 bytes 類型直接使用了str類型,因此:
python2中的字符串有3種類型:unicode、str、bytes,其中bytes和str爲同一個類型~
python3中的字符串有2種類型:str 和 bytes,str就是python2中的unicode,bytes就是python2中的str~

sys模塊中的getdefaultencoding和setdefaultencoding

使用sys模塊中的getdefaultencoding可獲取python的默認編碼方式:

# python2
import sys
print sys.getdefaultencoding()
輸出結果:
ascii

# python3
import sys
print(sys.getdefaultencoding())

輸出結果:
utf-8

能夠看到python2中的默認編碼是ascii,python3中的是utf-8。字符串在encode和decode時(轉換爲unicode或從unicode轉爲其餘編碼)默認使用getdefaultencoding輸出的編碼格式,這個在python2中應用較多,python3中因爲字符串一概使用unicode存放,因此應用較少~

python3中,當str類型(unicode)和bytes類型合併時,會直接報錯

x = '你好,'                               # str類型
y = '貝貝'.encode('utf-8')        # bytes類型
print(x + y)

報錯信息:
TypeError: must be str, not bytes

可是在python2中,這個過程能夠進行,Python解釋器會自動把 str 轉換成 unicode 再進行運算,運算結果也都是 unicode類型,在Python解釋器自動將 str 轉成 unicode時,因爲沒有具體指定使用哪一種編碼進行轉碼,因此python解釋器就會默認使用 getdefaultencoding中的編碼,python2中默認編碼是ascii,因而就出現以下錯誤:

# -*- coding: utf-8 -*-

x = u'你好,'
y = '貝貝'
print x + y

錯誤信息:
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe8 in position 0: ordinal not in range(128)

調整一下默認編碼,就能夠正常輸出:

# -*- coding: utf-8 -*-

import sys
reload(sys)
sys.setdefaultencoding('utf-8')
x = u'你好,'
y = '貝貝'
print x + y

輸出結果:
你好,貝貝

字符串打印到終端

python2中字符串直接輸出到終端 和 字符串的編碼標準(以什麼標準編碼存放在內存上)即 終端編碼有關(例如windows終端編碼爲gbk,pycharm終端編碼爲utf-8),二者一致,才能避免亂碼

python3中有所區別,字符串默認使用unicode格式保存在內存中,這樣不管輸出到哪一個終端都不會有亂碼問題;若將字符串轉爲其餘編碼格式,則終端不會將其轉爲字符格式,而是原樣輸出

x = '你好'
y = x.encode('utf-8')
print(type(x))
print(x)

print(type(y))
print(y)

pycharm 輸出結果:
<class 'str'>
你好
<class 'bytes'>
b'\xe4\xbd\xa0\xe5\xa5\xbd'

python字符編碼

二者輸出結果一致~.................^_^

相關文章
相關標籤/搜索