python全棧開發-Day6 字元編碼,python-day6

來源:互聯網
上載者:User

python全棧開發-Day6 字元編碼,python-day6
python全棧開發-Day6 字元編碼一 、瞭解字元編碼的知識儲備

一 、電腦基礎知識

 

二 、文字編輯器存取檔案的原理(nodepad++,pycharm,word)

#1、開啟編輯器就開啟了啟動了一個進程,是在記憶體中的,所以,用編輯器編寫的內容也都是存放與記憶體中的,斷電後資料丟失#2、要想永久儲存,需要點擊儲存按鈕:編輯器把記憶體的資料刷到了硬碟上。#3、在我們編寫一個py檔案(沒有執行),跟編寫其他檔案沒有任何區別,都只是在編寫一堆字元而已。

三、 python解譯器執行py檔案的原理 ,例如python test.py

#第一階段:python解譯器啟動,此時就相當於啟動了一個文字編輯器#第二階段:python解譯器相當於文字編輯器,去開啟test.py檔案,從硬碟上將test.py的檔案內容讀入到記憶體中(小複習:pyhon的解釋性,決定瞭解釋器只關心檔案內容,不關心檔案尾碼名)#第三階段:python解譯器解釋執行剛剛載入到記憶體中test.py的代碼( ps:在該階段,即真正執行代碼時,才會識別python的文法,執行檔案內代碼,當執行到name="egon"時,會開闢記憶體空間存放字串"egon")

四 、總結python解譯器與檔案本編輯的異同

#1、相同點:python解譯器是解釋執行檔案內容的,因而python解譯器具備讀py檔案的功能,這一點與文字編輯器一樣#2、不同點:文字編輯器將檔案內容讀入記憶體後,是為了顯示或者編輯,根本不去理會python的文法,而python解譯器將檔案內容讀入記憶體後,可不是為了給你瞅一眼python代碼寫的啥,而是為了執行python代碼、會識別python文法。
 二 字元編碼介紹

一 、什麼是字元編碼

  電腦要想工作必須通電,即用‘電’驅使電腦幹活,也就是說‘電’的特性決定了電腦的特性。電的特性即高低電平(人類從邏輯上將位元1對應高電平,位元0對應低電平),關於磁碟的磁特性也是同樣的道理。結論:電腦只認識數字  很明顯,我們平時在使用電腦時,用的都是人類能讀懂的字元(用進階語言編程的結果也無非是在檔案內寫了一堆字元),如何能讓電腦讀懂人類的字元?  必須經過一個過程:  #字元--------(翻譯過程)------->數字   #這個過程實際就是一個字元如何對應一個特定數位標準,這個標準稱之為字元編碼

二、 以下兩個情境下涉及到字元編碼的問題:

#1、一個python檔案中的內容是由一堆字元組成的,存取均涉及到字元編碼問題(python檔案並未執行,前兩個階段均屬於該範疇)#2、python中的資料類型字串是由一串字元組成的(python檔案執行時,即第三個階段)

三 、字元編碼的發展史與分類(瞭解)

  電腦由美國人發明,最早的字元編碼為ASCII,只規定了英文字母數字和一些特殊字元與數位對應關係。最多隻能用 8 位來表示(一個位元組),即:2**8 = 256,所以,ASCII碼最多隻能表示 256 個符號

當然我們程式設計語言都用英文沒問題,ASCII夠用,但是在處理資料時,不同的國家有不同的語言,日本人會在自己的程式中加入日文,中國人會加入中文。

而要表示中文,單拿一個位元組表表示一個漢子,是不可能表達完的(連小學生都認識兩千多個漢字),解決方案只有一個,就是一個位元組用>8位2進位代表,位元越多,代表的變化就多,這樣,就可以儘可能多的表達出不通的漢字

所以中國人規定了自己的標準gb2312編碼,規定了包含中文在內的字元->數位對應關係。

日本人規定了自己的Shift_JIS編碼

韓國人規定了自己的Euc-kr編碼(另外,韓國人說,電腦是他們發明的,要求世界統一用韓國編碼,但世界人民沒有搭理他們)

 

這時候問題出現了,精通18國語言的小周同學謙虛的用8國語言寫了一篇文檔,那麼這篇文檔,按照哪國的標準,都會出現亂碼(因為此刻的各種標準都只是規定了自己國家的文字在內的字元跟數位對應關係,如果單純採用一種國家的編碼格式,那麼其餘國家語言的文字在解析時就會出現亂碼)

所以迫切需要一個世界的標準(能包含全世界的語言)於是unicode應運而生(韓國人表示不服,然後沒有什麼卵用)

ascii用1個位元組(8位二進位)代表一個字元

unicode常用2個位元組(16位二進位)代表一個字元,生僻字需要用4個位元組

例:

字母x,用ascii表示是十進位的120,二進位0111 1000

漢字已經超出了ASCII編碼的範圍,用Unicode編碼是十進位的20013,二進位的01001110 00101101

字母x,用unicode表示二進位0000 0000 0111 1000,所以unicode相容ascii,也相容萬國,是世界的標準

 

這時候亂碼問題消失了,所有的文檔我們都使用但是新問題出現了,如果我們的文檔通篇都是英文,你用unicode會比ascii耗費多一倍的空間,在儲存和傳輸上十分的低效

本著節約的精神,又出現了把Unicode編碼轉化為“可變長編碼”的UTF-8編碼。UTF-8編碼把一個Unicode字元根據不同的數字大小編碼成1-6個位元組,常用的英文字母被編碼成1個位元組,漢字通常是3個位元組,只有很生僻的字元才會被編碼成4-6個位元組。如果你要傳輸的文本包含大量英文字元,用UTF-8編碼就能節省空間的:

字元 ASCII Unicode UTF-8
A 01000001 00000000 01000001 01000001
x 01001110 00101101 11100100 10111000 10101101

從上面的表格還可以發現,UTF-8編碼有一個額外的好處,就是ASCII編碼實際上可以被看成是UTF-8編碼的一部分,所以,大量只支援ASCII編碼的曆史遺留軟體可以在UTF-8編碼下繼續工作。

四 、總結字元編碼的發展可分為三個階段(重要)

基於目前的現狀,記憶體中的編碼固定就是unicode,我們唯一可變的就是硬碟的上對應的字元編碼。
此時你可能會覺得,那如果我們以後開發軟時統一都用unicode編碼,那麼不就都統一了嗎,關於統一這一點你的思路是沒錯的,但我們不可會使用unicode編碼來編寫程式的檔案,因為在通篇都是英文的情況下,耗費的空間幾乎會多出一倍,這樣在軟體讀入記憶體或寫入磁碟時,都會徒增IO次數,從而降低程式的執行效率。因而我們以後在編寫程式的檔案時應該統一使用一個更為精準的字元編碼utf-8(用1Bytes存英文,3Bytes存中文),再次強調,記憶體中的編碼固定使用unicode。
1、在存入磁碟時,需要將unicode轉成一種更為精準的格式,utf-8:全稱Unicode Transformation Format,將資料量控制到最精簡

2、在讀入記憶體時,需要將utf-8轉成unicode
所以我們需要明確:記憶體中用unicode是為了相容萬國軟體,即便是硬碟中有各國編碼編寫的軟體,unicode也有相對應的映射關係,但在現在的開發中,程式員普遍使用utf-8編碼了,估計在將來的某一天等所有老的軟體都淘汰掉了情況下,就可以變成:記憶體utf-8<->硬碟utf-8的形式了。

三 字元編碼應用之檔案編輯器3.1 文字編輯器之nodpad++

 

3.2 文字編輯器之pycharm

以utf-8格式開啟(選擇reload)

3.3 文字編輯器之python解譯器
檔案test.py以gbk格式儲存,內容為:  x='林'無論是  python2 test.py還是  python3 test.py都會報錯(因為python2預設ascii,python3預設utf-8)除非在檔案開頭指定#coding:gbk
3.4 總結

!!!總結非常重要的兩點!!!

#1、保證不亂嗎的核心法則就是,字元按照什麼標準而編碼的,就要按照什麼標準解碼,此處的標準指的就是字元編碼#2、在記憶體中寫的所有字元,一視同仁,都是unicode編碼,比如我們開啟編輯器,輸入一個“你”,我們並不能說“你”就是一個漢字,此時它僅僅只是一個符號,該符號可能很多國家都在使用,根據我們使用的IME不同這個字的樣式可能也不太一樣。只有在我們往硬碟儲存或者基於網路傳輸時,才能確定”你“到底是一個漢字,還是一個日本字,這就是unicode轉換成其他編碼格式的過程了

                  unicode----->encode-------->utf-8

                  utf-8-------->decode---------->unicode

#補充:瀏覽網頁的時候,伺服器會把動態產生的Unicode內容轉換為UTF-8再傳輸到瀏覽器如果服務端encode的編碼格式是utf-8, 用戶端記憶體中收到的也是utf-8編碼的結果。

 

四 字元編碼應用之python4.1 執行python程式的三個階段

python test.py   (我再強調一遍,執行test.py的第一步,一定是先將檔案內容讀入到記憶體中)

test.py檔案內容以gbk格式儲存的,內容為:

階段一:啟動python解譯器

階段二:python解譯器此時就是一個文字編輯器,負責開啟檔案test.py,即從硬碟中讀取test.py的內容到記憶體中

此時,python解譯器會讀取test.py的第一行內容,#coding:utf-8,來決定以什麼編碼格式來讀入記憶體,這一行就是來設定python解譯器這個軟體的編碼使用的編碼格式這個編碼,可以用sys.getdefaultencoding()查看,如果不在python檔案指定頭資訊#-*-coding:utf-8-*-,那就使用預設的python2中預設使用ascii,python3中預設使用utf-8 

 

改正:在test.py指定檔案頭,字元編碼一定要為gbk,

#coding:gbk你好啊

階段三:讀取已經載入到記憶體的代碼(unicode編碼格式),然後執行,執行過程中可能會開闢新的記憶體空間,比如x="egon"

記憶體的編碼使用unicode,不代表記憶體中全都是unicode,在程式執行之前,記憶體中確實都是unicode,比如從檔案中讀取了一行x="egon",其中的x,等號,引號,地位都一樣,都是一般字元而已,都是以unicode的格式存放於記憶體中的但是程式在執行過程中,會申請記憶體(與程式碼所存在的記憶體是倆個空間)用來存放python的資料類型的值,而python的字串類型又涉及到了字元的概念比如x="egon",會被python解譯器識別為字串,會申請記憶體空間來存放字串類型的值,至於該字串類型的值被識別成何種編碼存放,這就與python解譯器的有關了,而python2與python3的字串類型又有所不同。 
 4.2 python2與python3字串類型的區別

一 在python2中有兩種字串類型str和unicode

str類型

當python解譯器執行到產生字串的代碼時(例如x='上'),會申請新的記憶體位址,然後將'上'編碼成檔案開頭指定的編碼格式

要想看x在記憶體中的真實格式,可以將其放入列表中再列印,而不要直接列印,因為直接print()會自動轉換編碼,這一點我們稍後再說。

#coding:gbkx='上'y='下'print([x,y]) #['\xc9\xcf', '\xcf\xc2']#\x代表16進位,此處是c9cf總共4位16進位數,一個16進位四4個位元位,4個16進位數則是16個位元位,即2個Bytes,這就證明了按照gbk編碼中文用2Bytes
print(type(x),type(y)) #(<type 'str'>, <type 'str'>)

理解字元編碼的關鍵!!!

記憶體中的資料通常用16進位表示,2位16進位資料代表一個位元組,如\xc9,代表兩位16進位,一個位元組

gbk存中文需要2個bytes,而存英文則需要1個bytes,它是如何做到的???!!!

gbk會在每個bytes,即8位bit的第一個位作為標誌位,標誌位為1則表示是中文字元,如果標誌位為0則表示為英文字元

x=‘你a好’轉成gbk格式二進位位8bit+8bit+8bit+8bit+8bit=(1+7bit)+(1+7bit)+(0+7bit)+(1+7bit)+(1+7bit)

這樣電腦按照從左往右的順序讀:

#連續讀到前兩個括弧內的首位標誌位均為1,則構成一個中午字元:你#讀到第三個括弧的首位標誌為0,則該8bit代表一個英文字元:a#連續讀到後兩個括弧內的首位標誌位均為1,則構成一個中午字元:好

也就是說,每個Bytes留給我們用來存真正值的有效位元只有7位,而在unicode表中存放的只是這有效7位,至於首位的標誌位與具體的編碼有關,即在unicode中表示gbk的方式為:

(7bit)+(7bit)+(7bit)+(7bit)+(7bit)

 

按照翻譯的結果,我們可以去unicode關於漢字的對應關係中去查:連結:https://pan.baidu.com/s/1dEV3RYp

 

可以看到“”上“”對應的gbk(G0代表的是gbk)編碼就為494F,即我們得出的結果,而上對應的unicode編碼為4E0A,我們可以將gbk-->decode-->unicode

#coding:gbkx='上'.decode('gbk')y='下'.decode('gbk')print([x,y]) #[u'\u4e0a', u'\u4e0b']

unicode類型

當python解譯器執行到產生字串的代碼時(例如s=u'林'),會申請新的記憶體位址,然後將'林'以unicode的格式存放到新的記憶體空間中,所以s只能encode,不能decode

#coding:gbkx=u'上' #等同於 x='上'.decode('gbk')y=u'下' #等同於 y='下'.decode('gbk')print([x,y]) #[u'\u4e0a', u'\u4e0b']
print(type(x),type(y)) #(<type 'unicode'>, <type 'unicode'>)

列印到終端

對於print需要特別說明的是:

當程式執行時,比如

x='上' #gbk下,字串存放為\xc9\xcf

print(x) #這一步是將x指向的那塊新的記憶體空間(非代碼所在的記憶體空間)中的記憶體,列印到終端,按理說應該是存的什麼就列印什麼,但列印\xc9\xcf,對一些不熟知python編碼的程式員,立馬就懵逼了,所以龜叔自作主張,在print(x)時,使用終端的編碼格式,將記憶體中的\xc9\xcf轉成字元顯示,此時就需要終端編碼必須為gbk,否則無法正常顯示原內容:上

對於unicode格式的資料來說,無論怎麼列印,都不會亂碼

unicode這麼好,不會亂碼,那python2為何還那麼彆扭,搞一個str出來呢?python誕生之時,unicode並未像今天這樣普及,很明顯,好的東西你能看得見,龜叔早就看見了,龜叔在python3中將str直接存成unicode,我們定義一個str,無需加u首碼,就是一個unicode,屌不屌?

 

二 在python3 中也有兩種字串類型str和bytes

str是unicode

#coding:gbkx='上' #當程式執行時,無需加u,'上'也會被以unicode形式儲存新的記憶體空間中,print(type(x)) #<class 'str'>#x可以直接encode成任意編碼格式print(x.encode('gbk')) #b'\xc9\xcf'print(type(x.encode('gbk'))) #<class 'bytes'>

很重要的一點是:看到python3中x.encode('gbk') 的結果\xc9\xcf正是python2中的str類型的值,而在python3是bytes類型,在python2中則是str類型

於是我有一個大膽的推測:python2中的str類型就是python3的bytes類型,於是我查看python2的str()源碼,發現

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.