Python的字符編碼

本篇內容涉及

  1. 二進制
  2. 二進制與ASCII碼
  3. 字符編碼的發展與介紹
  4. 十六進制

 

二進制


相信你們都知道進制的含義,咱們使用最普遍也最貼近實際生活的就是十進制,逢十進1、借一當十。在其餘領域中被普遍使用的還有二進制、八進制和十六進制,每種進制都有其有點和擅長的領域。二進制是計算技術中普遍採用的一種數制。二進制數是用0和1兩個數碼來表示的數。它的基數爲2,進位規則是「逢二進一」,借位規則是「借一當二」。當前的計算機系統使用的基本上是二進制系統,數據在計算機中主要是以補碼的形式存儲的。計算機中的二進制則是一個很是微小的開關,用「開」來表示1,「關」來表示0,由於計算機內部的CPU包含上百萬個精巧的晶體管的芯片集合的集成電路,一條路要麼就經過,要麼就關閉,用二進制的 0、1 最爲合適了。這也是爲何布爾值的True和False對應一、0了。固然一些運算也會涉及到八進制、十進制、十六進制,它們的轉換關係如何呢?python

這裏先給你們介紹三個內置方法(BIF built-in function),所謂內置方法,就是爲了方便寫代碼,能夠直接調用的方法,例如print、input等。這三個內置方法用來進行進制轉換,括號內輸入十進制整數,轉換後獲得字符串。編程

   二進制轉換:bin() ---> ‘0b’(01)數組

   八進制轉換:oct() ---> ‘0o’(01234567)網絡

十六進制準換:hex() ---> ‘0x’(0123456789abcdef)ui

>>> a = 10
>>> bin(a),oct(a),hex(a) ('0b1010', '0o12', '0xa')

 

二進制與ASCII碼


計算機只認識二進制,生活中的數字要想讓計算機理解就必須轉換成二進制。十進制到二進制的轉換隻能解決計算機理解數字的問題,那麼文字要怎麼讓計算機理解呢?這時,ASCII碼應運而生。將計算機須要識別的文字、符號、數字等等編輯在一張表裏,每個字符都對應一個十制數,再把這個十進制數轉換成二進制,計算機就認識了。編碼

ascii

ASCII(American Standard Code for Information Interchange,美國信息交換標準代碼)是基於拉丁字母的一套電腦編碼系統,主要用於顯示現代英語和其餘西歐語言。它是現今最通用的單字節編碼系統,並等同於國際標準ISO/IEC 646。最先只有127個字母被編碼到計算機裏,後來擴展了一些亂七八糟的的東西進去變成255個,正好被8位二進制數表示。因此就肯定無論是哪一個字符,都要以8位二進制數來表示,便於計算機識別,不然很容易亂。spa

好比我如今想表示 ‘hello’,應該以下:翻譯

hello

在這裏,每一位0或者1所佔的空間單位爲bit(比特),這是計算機中最小的表示單位,每8個bit組成一個字節byte,用B來表示。這是計算機中最小的存儲單位(畢竟你是沒有辦法存儲半個字符的)。設計

8bit = 1byte 字節,最小的存儲單位,1byte縮寫爲1B  1KB=1024B
1MB=1024KB
1GB=1024MB
1TB=1024GB 等等。。。

 

字符編碼的發展介紹


因爲計算機在美國發明,固然沒有考慮到別的國家也須要識別本國字符,尤爲像中國,歷史悠久,須要編碼識別的字更是數不勝數。3d

GB2312

當計算機來到中國,根本就不認識中國的文字,壯哉我大中國自力更生,本身重寫一張表,直接生猛地將擴展的第八位對應拉丁文所有刪掉,規定一個小於127的字符的意義與原來相同,原本128-255之間的字符使用頻率極低,連續使用兩次機率更低,因此兩個大於127的字符連在一塊兒時,就表示一個漢字,前面的一個字節(他稱之爲高字節)從0xA1用到0xF7,後面一個字節(低字節)從0xA1到0xFE,高低字節組合相似於橫縱座標,這樣咱們就能夠組合出大約7000多個簡體漢字了;這種漢字方案叫作 「GB2312」。GB2312 啓用於1980年,是對 ASCII 的中文擴展。 只收錄簡化字漢字,以及通常經常使用字母和符號,主要通行於中國大陸地區和新加坡等地,共收錄有 7445 個字符,其中簡化漢字 6763 個,字母和符號 682 個。

GBK

可是漢字太多了,GB2312根本不夠用,因而規定:只要第一個字節是大於127就固定表示這是一個漢字的開始,無論後面跟的是否是擴展字符集裏的內容。擴展以後的編碼方案被稱爲 GBK 標準,GBK 包括了 GB2312 的全部內容,同時又增長了近20000個新的漢字(包括繁體字)和符號。GBK編碼方案於1995年10月制定, 1995年12月正式發佈,兼容GB2312,共有23940個碼位,共收錄了21003個漢字。

GB18030

GB18030有兩個版本:GB18030-2000和GB18030-2005。GB18030-2000是GBK的取代版本,它的主要特色是在GBK基礎上增長了CJK統一漢字擴充A的漢字。GB18030-2005的主要特色是在GB18030-2000基礎上增長了CJK統一漢字擴充B的漢字。GB18030-2000僅規定了經常使用非漢字符號和27533個漢字(包括部首、部件等)的編碼。GB18030-2005在GB18030-2000的基礎上增長了42711個漢字和多種我國少數民族文字的編碼。

Unicode

在中國字符編碼蓬勃發展的時候,其餘國家也在擴展本身的字符編碼,如日本的Shift-JIS、韓國的ks_c_5601-1987等等,彼此之間倒是互不支持的。這就致使每一個國家都有本身的編碼,拿着我國的編碼到日本就變成亂碼。因而,國際標誰化組織爲了統一編碼:提出了標準編碼準則:Unicode 。Unicode是能夠容納世界上全部文字和符號的字符編碼方案。目前的Unicode字符分爲17組編排,0x0000 至 0x10FFFF,每組稱爲平面(Plane),而每平面擁有65536個碼位,共1114112個。然而目前只用了少數平面。Unicode在1990年開始研發,1994年正式公佈。Unicode編碼,每個字符都是由16位二進制數組成的,大小爲兩個字節。因爲Python的誕生比Unicode標準發佈的時間還要早,因此最先的Python2.x版本默認編碼爲ASCII碼。

utf-8

Unicode字符編碼兼容ASCII碼,可是卻比原ASCII碼裏的字符比原來大了一倍。這下英文世界的人們不幹了,由此產生了新的編碼規則,UTF-8。UTF-8(8-bit Unicode Transformation Format)是一種針對Unicode的可變長度字符編碼,當字符在ASCII碼的範圍時,就用一個字節表示。可是對其他地區不太友好,歐洲語系須要2個字節、東亞地區須要3個字節,其它及特殊字符會須要4個字節等等。不過寫代碼嘛,用到的中文不多,因此也就不在意了。雖然在咱們內存中的數據都是unicode,但當數據要保存到磁盤或者用於網絡傳輸時,直接使用unicode就遠不如utf-8省空間啦! 這也是爲何utf-8是咱們的推薦編碼方式。 總結來講:UTF 是爲unicode編碼 設計 的一種 在存儲 和傳輸時節省空間的編碼方案。


 

十六進制


先給你們看一個例子,還記得字符串的encode()方法吧:

QQ截圖20190213215210

不是說計算機都是用二進制的麼?爲何轉換成bytes類型後顯示的倒是十六進制呢?這是由於十六進制更簡短,一位十六進制數等於4位二進制數。比方說ASCII碼,是由8bit表示一個字符,那麼若是用十六進制只須要2位就能夠了,雖然這個樣子咱們仍是看不懂,可是這種表現形式仍是要優於0101的,最後爲了統一規範,CPU、內存等都是採用十六進制。不僅是計算機,在網絡編程的數據傳輸也是經過十六進制傳輸的。

二進制與十六進制相互轉換

熟記這個對應表,轉換過程會事半功倍。

16進制2進制對應關係

二進制到十六進制

二進制到十六進制,採用去四合一法,以小數點爲分界,整數部分向左、小數部分向右,每四位二進制換成一位十六進制,小數點位置保持不變。若是到最高位(或最低)不足四位,直接在最高位(或最低)補0。轉換完後,如何分辨這個數是那種進制呢?十六進制的表示法,須要加上前綴‘0x’或者後綴‘h’,像剛剛看到的計算機裏表示方法是使用前綴,可是把0省略了。

QQ截圖20190214095955

十六進制到二進制

十六進制到二進制,就是反過來,每一個十六進制位都用四個二進制替換,小數點依然位置不動。

QQ截圖20190214101425


 

字符編碼


說了這麼多,字符編碼和寫程序有什麼關係呢?這裏關係但是太大了。首先,咱們在計算機內存儲的數據或者是進行網絡傳輸的數據,必定是要按照某一種編碼格式,這樣計算機才能根據該編碼格式將數據轉換成0101的格式進行操做,而要讀取數據和接收數據時,也是必定要按照相同的編碼格式來,不然就會出現亂碼。

>>> s = "你好"
>>> s.encode('utf-8') b'\xe4\xbd\xa0\xe5\xa5\xbd'
>>> s.encode('gbk') b'\xc4\xe3\xba\xc3'
>>> # 能夠看出,utf-8和gbk編碼的長度都是不同的

代碼的編碼(文件編碼)

首先一個程序的代碼也就是源代碼文件是有編碼格式的,因此你編寫的代碼也必定是按照事先規定好的編碼格式存儲、執行或傳輸的。在Python3.x版本後,當咱們在寫一個代碼腳本的時候,發現咱們根本就沒有這麼一個步驟去告訴Python解釋器這些代碼是什麼格式的編碼。那是由於Python有默認的字符編碼,那就是<utf-8>,也就是說你不用刻意地告訴Python這些代碼應該按什麼編碼格式存儲,Python已經幫你設置好了。固然代碼的編碼能夠根據你的需求更改。相信在看過一些代碼或者腳本後,你會發現好多人代碼的第一行都有這樣一句:

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

沒錯,這句話就是聲明接下來你要寫的全部代碼應該按照何種編碼格式存儲和執行。由於Python3.x版本後默認就是utf-8,而且多數程序也都是以utf-8格式寫的,因此並不須要強加這句。固然,若是你要改的話,比方說改爲gbk格式,那就必要在最最最最上面加上這句話,聲明整篇都是gbk。

# -*- coding:gbk –*-

因此說Python代碼執行的過程大體上是這樣的:

1. 首先寫好的 .py 文件會按照文件頭聲明的編碼格式存儲到硬盤上(encode編碼),若是沒有指定編碼格式就按照默認的編碼格式來。

2. 要運行文件時,解釋器首先找到 .py 文件,將文件按照開頭指定的編碼格式將代碼加載到內存中,並所有轉換成unicode格式。

3. 而後就是開始對代碼進行解釋,最後執行。

補充:咱們能夠經過Python自帶模塊來查看當前的解釋器的默認編碼。

# Python2
import sys sys.getdefaultencoding() # 輸出'ascii'

# Python3
import sys sys.getdefaultencoding() # 輸出'utf-8'

字符串的編碼

再說字符串的編碼以前,必定要區分好字符串和字節串。字符串就是咱們能直觀看懂的,平常生活中使用的溝通交流的語言符號。而字節串是計算機能看懂的一堆二進制碼。字符不等於字節,可是二者之間存在轉換關係(字符編碼)。根據選取的字符集的不一樣轉換結果不同,也就是咱們上面所說的各類字符編碼。而在Python3.x中已經實現了unicode的內置支持,而Python3.x中字符的形式只有兩種一種就是以unicode格式顯示的字符串,一種就是bytes類型的字節串。以unicode格式顯示的字符串是直接可讀的,因此只有unicode是真正的字符串。

# unicode字符串
str1 = '你好'

# bytes類型字節串
str2 = b'abc'  # 字符串前加b就表示bytes類型,這種寫法只支持ascii碼
str3 = b'\xe4\xbd\xa0\xe5\xa5\xbd'  # '你好'轉換的字節串

因爲Python3.x定義的字符串默認就是unicode,而且unicode編碼含有全部字符編碼的映射關係,因此unicode格式的字符串沒辦法被decode(解碼)操做,只能進行encode(編碼)操做,轉換成爲utf-八、gbk、gb2312等編碼格式的bytes類型字節串。而字節串能夠經過decode(解碼)操做轉換回unicode格式。之間的轉換關係以下圖:

字符編碼轉換關係

各個字符編碼在轉換的時候必定不要混搭,不然就會出現下面的狀況(亂碼或者不是原來的樣子):

>>> a = '你好'  # 此時必定是unicode編碼
>>> b = a.encode('utf-8')  # b從unicode轉換成utf-8
>>> b b'\xe4\xbd\xa0\xe5\xa5\xbd'
>>> c = b.decode('gbk')  # c按照gbk編碼轉換成unicode
>>> c '浣犲ソ' 
# 轉換回去已經不是'你好'了

一個字符串按照某種編碼格式編碼成字節串,這個字節串想要解碼成字符串必定要遵守以前的編碼格式,好比中文按照utf-8編碼,每一個字符是三個字節,而按照gbk解碼成字符串時每一個字符只有兩個字節,這樣在字符完成解碼時,至少字符個數上就會發生變化,若是編碼的互相對應不上的話就會出現亂碼。

 

PS:任何一種編碼都不會解決語言種類的問題。比方說用日本的編碼格式Shift_JIS編寫的軟件拿到中國來,通常中國的Windows系統默認編碼都是gbk格式,以gbk去顯示Shift_JIS確定是對應不上的,因此該軟件沒法正常顯示。可是電腦都支持unicode,若是把軟件的編碼轉換爲unicode,而Unicode又包含全部編碼的映射,這樣就能夠正常顯示了,可是必定注意,顯示的是日文,而不是中文,正常顯示的意思就是顯示的是正確的字符,但可沒有解決翻譯語言的問題。

 

 總結

若是在Python3.x中出現字符編碼的問題,那麼無外乎就是下面幾種狀況:

1. Python解釋器默認編碼

2. py文件源代碼的編碼

3. 字符串和字節串的編碼

4. 系統默認編碼

以上這幾處所使用的編碼沒有對應好。


 

python2.x簡介

Python2的默認編碼是ASCII碼,這就致使python想要顯示中文等必需要在文件頭聲明字符編碼。

python2中,字符串有三個類型:str、bytes、unicode。str和bytes兩類是能夠直接劃等號的,都屬於字節串。而unicode纔是真正的字符串。因此當你定義一個 str類型變量的時候,你覺得是字符串,其實就是bytes類型。

最後,爲了知足pytohn2 和 python3 的兼容性,儘可能在文件頭加上 # -*- coding:gbk –*-

相關文章
相關標籤/搜索