網站首頁 編程語言 正文
一、了解字符編碼的知識儲備
1. 文本編輯器存取文件的原理(nodepad++,pycharm,word)
?打開編輯器就打開了啟動了一個進程,是在內存中的,所以在編輯器編寫的內容也都是存放與內存中的,斷電后數據丟失,因而需要保存到硬盤上,點擊保存按鈕,就從內存中把數據刷到了硬盤上。在這一點上,我們編寫一個py文件(沒有執行),跟編寫其他文件沒有任何區別,都只是在編寫一堆字符而已。
即:在沒有點擊保存時,我們所寫的內容都是寫入內存。注意這一點,很重要!!當我們點擊保存,內容才被刷到硬盤。
上面做了兩件事:寫內容到內存,從內存將內存刷到硬盤。這是兩個過程。
2. python解釋器執行py文件的原理?
例如:python test.py
- 第一階段:python解釋器啟動,此時就相當于啟動了一個文本編輯器
- 第二階段:python解釋器相當于文本編輯器,去打開test.py文件,從硬盤上將test.py的文件內容讀入到內存中
- 第三階段:python解釋器解釋執行剛剛加載到內存中test.py的代碼
python解釋器執行py文件分為兩個步驟:1.將文件讀到內存,2.解釋執行內容。
二、字符編碼簡介
要搞清楚字符編碼,首先要解決的問題是:什么是字符編碼?
我們都知道,計算機要想工作必須通電,也就是說‘電’驅使計算機干活,而‘電’的特性,就是高低電平(高低平即二進制數1,低電平即二進制數0),也就是說計算機只認識數字(010101).如果我們想保存數據,首先得將我們的數據進行一些處理,最終得轉換成010101才能讓計算機識別。
所以必須經過一個過程:
字符--------(翻譯過程)------->數字?
這個過程實際就是一個字符如何對應一個特定數字的標準,這個標準稱之為字符編碼。
那么問題就來了?作為一種編碼方案,還得解決兩個問題:
- a.字節是怎么分組的,如8 bits或16 bits一組,這也被稱作編碼單元。
- b.編碼單元和字符之間的映射關系。例如,在ASCII碼中,十進制65映射到字母A上。
ASCII碼是上個世紀最流行的編碼體系之一,至少在西方是這樣。下圖顯示了ASCII碼中編碼單元是怎么映射到字符上的。
三、字符編碼的發展史
階段一:現代計算機起源于美國,最早誕生也是基于英文考慮的ASCII
隨著計算機越來越流行,廠商之間的競爭更加激烈,在不同的計算機體系間轉換數據變得十分蛋疼,人們厭煩了這種自定義造成的混亂。最終,計算機制造商一起制定了一個標準的方法來描述字符。他們定義使用一個字節的低7位來表示字符,并且制作了如上圖所示的對照表來映射七個比特的值到一個字符上。例如,字母A是65,c是99,~是126等等, ASCII碼就這樣誕生了。原始的ASCII標準定義了從0到127 的字符,這樣正好能用七個比特表示。
為什么選擇了7個比特而不是8個來表示一個字符呢?我并不關心。但是一個字節是8個比特,這意味著1個比特并沒有被使用,也就是從128到255的編碼并沒有被制定ASCII標準的人所規定,這些美國人對世界的其它地方一無所知甚至完全不關心。其它國家的人趁這個機會開始使用128到255范圍內的編碼來表達自己語言中的字符。例如,144在阿拉伯人的ASCII碼中是?,而在俄羅斯的ASCII碼中是?。ASCII碼的問題在于盡管所有人都在0-127號字符的使用上達成了一致,但對于128-255號字符卻有很多很多不同的解釋。你必須告訴計算機使用哪種風格的ASCII碼才能正確顯示128-255號的字符。
總結:ASCII,一個Bytes代表一個字符(英文字符/鍵盤上的所有其他字符),1Bytes=8bit,8bit可以表示0-2**8-1種變化,即可以表示256個字符,ASCII最初只用了后七位,127個數字,已經完全能夠代表鍵盤上所有的字符了(英文字符/鍵盤的所有其他字符),后來為了將拉丁文也編碼進了ASCII表,將最高位也占用了。
階段二:為了滿足中文,中國人定制了GBK
GBK:2Bytes代表一個字符;為了滿足其他國家,各個國家紛紛定制了自己的編碼。日本把日文編到Shift_JIS里,韓國把韓文編到Euc-kr里
階段三:萬國碼Unicode
編碼
后來,有人開始覺得太多編碼導致世界變得過于復雜了,讓人腦袋疼,于是大家坐在一起拍腦袋想出來一個方法:所有語言的字符都用同一種字符集來表示,這就是Unicode。
Unicode統一用2Bytes代表一個字符,2**16-1=65535
,可代表6萬多個字符,因而兼容萬國語言.但對于通篇都是英文的文本來說,這種編碼方式無疑是多了一倍的存儲空間(英文字母只需要一個字節就足夠,用兩個字節來表示,無疑是浪費空間).于是產生了UTF-8,對英文字符只用1Bytes表示,對中文字符用3Bytes.UTF-8
是一個非常驚艷的概念,它漂亮的實現了對ASCII碼的向后兼容,以保證Unicode可以被大眾接受。
在UTF-8中,0-127號的字符用1個字節來表示,使用和US-ASCII相同的編碼。這意味著1980年代寫的文檔用UTF-8打開一點問題都沒有。只有128號及以上的字符才用2個,3個或者4個字節來表示。因此,UTF-8被稱作可變長度編碼。
于是字節流:0100100001000101010011000100110001001111
這個字節流在ASCII和UTF-8中表示相同的字符:HELLO
至于其他的UTF-16,這里就不再敘述了。
總結一點:unicode:簡單粗暴,所有字符都是2Bytes,優點是字符----->數字的轉換速度快,缺點是占用空間大。
utf-8:精準,對不同的字符用不同的長度表示,優點是節省空間,缺點是:字符->數字的轉換速度慢,因為每次都需要計算出字符需要多長的Bytes才能夠準確表示。
因此,內存中使用的編碼是unicode,用空間換時間(程序都需要加載到內存才能運行,因而內存應該是盡可能的保證快);硬盤中或者網絡傳輸用utf-8,網絡I/O延遲或磁盤I/O延遲要遠大與utf-8的轉換延遲,而且I/O應該是盡可能地節省帶寬,保證數據傳輸的穩定性。
所有程序,最終都要加載到內存,程序保存到硬盤不同的國家用不同的編碼格式,但是到內存中我們為了兼容萬國(計算機可以運行任何國家的程序原因在于此),統一且固定使用unicode,這就是為何內存固定用unicode的原因,你可能會說兼容萬國我可以用utf-8啊,可以,完全可以正常工作,之所以不用肯定是unicode比utf-8
更高效啊(uicode固定用2個字節編碼,utf-8則需要計算),但是unicode更浪費空間,沒錯,這就是用空間換時間的一種做法,而存放到硬盤,或者網絡傳輸,都需要把unicode
轉成utf-8
,因為數據的傳輸,追求的是穩定,高效,數據量越小數據傳輸就越靠譜,于是都轉成utf-8格式的,而不是unicode。
四、字符編碼的使用
不管是哪種類型的文件,只要記住一點:文件以什么編碼保存的,就以什么編碼方式打開.
下面我們來看看python中關于編碼出現的問題:
如果不在python文件指定頭信息#-*-coding:utf-8-*-
,那就使用默認的python2中默認使用ascii,python3中默認使用utf-8
讀取已經加載到內存的代碼(unicode編碼的二進制),然后執行,執行過程中可能會開辟新的內存空間,比如x="hello"
內存的編碼使用unicode,不代表內存中全都是unicode編碼的二進制,在程序執行之前,內存中確實都是unicode編碼的二進制,比如從文件中讀取了一行x="hello"
,其中的x,等號,引號,地位都一樣,都是普通字符而已,都是以unicode編碼的二進制形式存放與內存中的.但是程序在執行過程中,會申請內存(與程序代碼所存在的內存是倆個空間),可以存放任意編碼格式的數據,比如x="hello",會被python解釋器識別為字符串,會申請內存空間來存放"hello",然后讓x指向該內存地址,此時新申請的該內存地址保存也是unicode編碼的hello,如果代碼換成x="hello".encode('utf-8')
,那么新申請的內存空間里存放的就是utf-8編碼的字符串hello了.
瀏覽網頁的時候,服務器會把動態生成的Unicode內容轉換為UTF-8再傳輸到瀏覽器
如果服務端encode的編碼格式是utf-8, 客戶端內存中收到的也是utf-8編碼的二進制
五、Python2與python3編碼區別
1.在python2中有兩種字符串類型str和unicode
str類型:
當python解釋器執行到產生字符串的代碼時(例如s='林'),會申請新的內存地址,然后將'林'編碼成文件開頭指定的編碼格式,這已經是encode之后的結果了,所以s只能decode。再次encode就會報錯。
#_*_coding:gbk_*_ 2 #!/usr/bin/env python 3? 4 x='林' 5 # print x.encode('gbk') #報錯 6 print x.decode('gbk') #結果:林
在python2中,str就是編碼后的結果bytes,str=bytes,所以在python2中,unicode字符編碼的結果是str/bytes。
#coding:utf-8 s='林' #在執行時,'林'會被以conding:utf-8的形式保存到新的內存空間中 print repr(s) #'\xe6\x9e\x97' 三個Bytes,證明確實是utf-8 print type(s) #s.decode('utf-8') # s.encode('utf-8') #報錯,s為編碼后的結果bytes,所以只能decode
Unicode類型:
當python解釋器執行到產生字符串的代碼時(例如s=u'林'),會申請新的內存地址,然后將'林'以unicode的格式存放到新的內存空間中,所以s只能encode,不能decode.
s=u'林' print repr(s) #u'\u6797' print type(s) ## s.decode('utf-8') #報錯,s為unicode,所以只能encode s.encode('utf-8')?
特別說明:
當數據要打印到終端時,要注意一些問題.
當程序執行時,比如:x='林';print(x) #這一步是將x指向的那塊新的內存空間(非代碼所在的內存空間)中的內存,打印到終端,而終端仍然是運行于內存中的,所以這打印可以理解為從內存打印到內存,即內存->內存,unicode->unicode.對于unicode格式的數據來說,無論怎么打印,都不會亂碼.python3中的字符串與python2中的u'字符串',都是unicode,所以無論如何打印都不會亂碼.在windows終端(終端編碼為gbk,文件編碼為utf-8,亂碼產生)
#分別驗證在pycharm中和cmd中下述的打印結果 s=u'林' #當程序執行時,'林'會被以unicode形式保存新的內存空間中 #s指向的是unicode,因而可以編碼成任意格式,都不會報encode錯誤 s1=s.encode('utf-8') s2=s.encode('gbk') print s1 #打印正常否? print s2 #打印正常否 print repr(s) #u'\u6797' print repr(s1) #'\xe6\x9e\x97' 編碼一個漢字utf-8用3Bytes print repr(s2) #'\xc1\xd6' 編碼一個漢字gbk用2Bytes print type(s) #print type(s1) # print type(s2) #
2. 在python3中也有兩種字符串類型str和bytes
str類型變為unicode類型:
#coding:utf-8 s='林' #當程序執行時,無需加u,'林'也會被以unicode形式保存新的內存空間中, #s可以直接encode成任意編碼格式 s.encode('utf-8') s.encode('gbk') print(type(s)) #
bytes類型:
#coding:utf-8 s='林' #當程序執行時,無需加u,'林'也會被以unicode形式保存新的內存空間中, #s可以直接encode成任意編碼格式 s1=s.encode('utf-8') s2=s.encode('gbk') print(s) #林 print(s1) #b'\xe6\x9e\x97' 在python3中,是什么就打印什么 print(s2) #b'\xc1\xd6' 同上 print(type(s)) #print(type(s1)) # print(type(s2)) #
原文鏈接:https://www.cnblogs.com/vipchenwei/p/6993788.html
相關推薦
- 2023-06-04 Pandas.DataFrame重置列的行名實現(set_index)_python
- 2022-03-14 使用npm安裝淘寶鏡像(npm配置淘寶鏡像)
- 2022-09-22 繼承關系下構造方法的訪問特點
- 2022-09-26 淺談Redis如何應對并發訪問_Redis
- 2022-06-22 Python?裝飾器常用的創建方式及源碼示例解析_python
- 2022-03-23 C++?Boost?PropertyTree解析INI文件詳解_C 語言
- 2023-07-16 unipp 小程序 退出登錄
- 2022-04-12 Python數據可視化Pyecharts庫的使用教程_python
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支