先簡單介紹一下編碼的情況,我們都知道機器上顯示的字符最終存在計算機內存里都是以二進制碼的形式存在的。
最開始的計算機字符只能用ASCII編碼的方式去存儲,而一個ASCII碼占用一個字節,也就是說ASCII編碼最多只能編碼256個字符(鍵盤上所有的半角字符)。 但為了表示別的國家文字,就必須對原有的字符編碼方式進行擴充。而對於中文來說,主要有兩種編碼方式,分別是gb2312和gbk,前者主要是用於編碼簡體中文字符,而后者除了簡體中文字符還包括繁體中文字符。計算機迅速國際化之后,編碼便不能只局限於英文字符和中文字符,於是出現了一個叫Unicode編碼的方式,這種編碼方式對每個字符都使用四個字節的方式存儲,這樣一來就足夠表示所有字符了,但事實上所有的半角字符我們只需要1個字節來表示便足夠了,全部字符都用Unicode編碼方式的話,很容易造成資源浪費的情況,所以作為折中的考慮,UTF-8逐漸成為全球的流行的編碼標准,UTF-8編碼能夠根據字符分別不同的字節大小,英文字符依然用一個字節表示,而中文有些則是兩個字節表示,有些則是三個字節。
本文直接通過三個例子來講解字符編碼和解碼的原理:
- 記事本字符的編碼
- 前端頁面中的<meta charset='utf-8'>
- 編程語言中讀寫文件的編碼(python3.x)
顧名思義,編碼就是把一個字符編碼成二進制碼存起來的方式,而解碼就是把這個二進制碼按照原本編碼的規則還原成原來的字符。
1. 記事本字符編碼
當我們打開記事本,然后打下一行字符的時候,對機器來說都是一串不可識別的字符,於是我們保存的時候,就是要對這些我們輸入的字符進行編碼了。如果你輸入一串非英文字符,計算機會提醒你有些字符不能正確編碼(windows中文版的話沒有這種情況,因為你按下ctrl+s計算機會有一個默認的中文編碼方式,則沒有出現無法編碼的情況。此處指的是英文版操作系統,當然中文操作系統也可以自主選擇編碼方式的,請往下看~),如下圖:
這個提示是說,如果你把這個文本保存為ANSI編碼的文本文件時,有些Unicode字符會丟失,問你是否確定,我們先點ok保存,看看文本效果:
當我們去打開的時候,和編碼相對的概念,解碼就要用到了,系統會檢測到這個文本是一個ANSI文本,於是用ASCII編碼方式去解碼,結果無法正常解析,出現亂碼,情理之中。(這是英文系統會出現的步驟,中文系統的測試由此處開始)。
我們刪除這個文件,重新建立一個,然后輸入同樣的內容,此時不要直接保存,點擊 【文件】-->【另存為】,下面有選擇編碼的下拉列表,我的機器記事本只能使用四種編碼方式(如下所示)
我們選擇UTF-8,保存,沒有出現任何提示,打開文本,內容正常顯示(如下圖所示)。
2. 前端頁面中的<meta charset='utf-8'>
然后我們注意到寫網站的時候我們會寫<meta charset='utf-8'>,這里指定的utf-8是指定編碼方式還是解碼方式呢,其實都不是,由上面所述,編碼方式取決於我們寫完文本之后保存所選擇的編碼方式。而瀏覽器解碼呢,取決於瀏覽器的設置(這個表述並不准確,請往下看,就會明朗),這個設置當然也是可以自己修改的,在這里:
咦,怎么還有這個東西~
回到前面meta里面指定的編碼有什么用呢,這里的編碼是你手工告訴瀏覽器說你這個網頁是使用什么編碼去保存的,然后用瀏覽器去打開的時候,瀏覽器會用本身設置的編碼方式去解碼內容,當遇到<meta charset='utf-8'>的時候,瀏覽器會放棄設置中的方式,改用你指定的charset去解碼內容,以保證內容都能正常顯示,下面我們來測試一下:
新建一個Test.html,用notepad++(為了方便)打開,選擇編碼方式為gb2312(nodepad++設置:【編碼】-->【編碼字符集】-->【中文】->【GB2312】),然后寫下代碼(如下圖所示),在這里我們“騙”瀏覽器說我們用utf-8編碼(但事實上我們是用GB2312啊):
然后用ie打開看看效果:
瀏覽器“被騙“之后,果然不能正確解碼內容了,然后我們此時強制把瀏覽器的編碼方式設置為GB2312,不能刷新(為什么?),結果如下:
我們不管瀏覽器了,編輯Test.html,保存編碼方式為UTF-8,然后刷新(此時瀏覽器編碼方式還是GB2312),瀏覽器解析到<meta charset='utf-8'>的時候,則使用utf-8編碼方式,結果就能正常顯示.了...
3. 編程語言中讀寫文件的編碼
在學習過程中,很多人會拋出一串亂碼求解決方案,而很多人的建議就是使用UTF-8,反正不知道為什么,編碼錯了,就用UTF-8試試,當改成UTF-8之后(python中就是在文件第一行加上#encoding:utf-8或者對字節碼使用.decode('utf-8')之類),還不能成功的話,接下來就不知道怎么做了。 這種做法都只是碰運氣嘗試,並沒有針對性修改,當理解了這種情況之后,面對編碼問題並不難解決。
既然問題是從python學習過程中跑出來的,那就用python再寫一個例子好了,用open去寫文件的時候可以傳入一個encoding參數用於指定編碼方式,同樣的,讀文件的時候encoding參數就視作解碼方式。我們編寫以下python代碼:
path = r'C:\Test\test.txt' with open(path, 'w', encoding='gb2312') as f: f.write("測試編碼") with open(path, 'r', encoding='utf-8') as f: print(f.read())
運行查看結果,很明顯吧,解碼錯誤~
我們用UTF-8去解碼文本,結果報錯說這不是UTF-8編碼。
把代碼 with open(path, 'r', encoding='utf-8') as f: 修改為 with open(path, 'r', encoding='gb2312') as f: ,重新運行py文件運行,結果如下
如果一開始我們不加encoding這個參數,打印的內容也能正常顯示,由上述可知,當我們打開一個文件的時候,系統檢測到這個文件的編碼方式,然后去解碼文件內容的,但我們在用python讀文件的時候並沒有去“打開文件“這個步驟啊, 這就需要用到上述提到的#encoding:utf-8的作用了,這句注釋指定了我們當前py文件的默認編碼方式,我們編寫py文件的時候,都有一個默認的編碼方式,然后這份代碼的編碼和解碼(如果沒有特別指定的話),都會按照這個方式來進行,這就解釋了我們讀的時候是應該是字節碼,打印出來卻是字符的原因了,是python解釋器用默認編碼方式解碼,幫我們做了這個步驟。
同樣的道理,我們去爬一個網頁內容的時候也是,爬到的是字節碼,然后我們要調用decode()方法對字節碼進行解碼,所以現在就知道如果出現亂碼,原因應該從哪里找起了吧,並不是都是簡單一句“試試UTF-8”就能解決所有情況的。
至此,以上為本人對字符編碼與解碼的一些拙見,如有不妥之處,敬請提出斧正。
尊重知識產權,轉載引用請通知作者並注明出處!