最近在socket中遇到了一個偶現bug,那就是與websocket創建鏈接後,進行數據傳輸後,在linux平臺的終端下用
socket_read()
讀取出來後,再用echo
打印出來的就是亂碼。由於我作的只是一個數據中轉,而另外一端的C++
則是用字節判斷,而不是用字符串判斷,而瀏覽器端的編碼是utf-8
,不知道爲什麼會這樣。這個問題在這個項目於結束後,終於有時間來糾結這個問題。固然,在一塊兒的糾結的還有python
的編碼。此次就先說一說python
的編碼問題。python
以前的一篇文章對一些基本的python編碼問題作了比較表面的解釋,有興趣的能夠點擊這裏去看一下我對python編碼的基礎理解。好了,下面先提出我碰到的問題。linux
# windows 10 powershell >>> u'知乎' u'\u77e5\u4e4e' >>> u'知乎'.encode('utf-8') '\xe7\x9f\xa5\xe4\xb9\x8e' >>> u'知乎'.encode('gbk') '\xd6\xaa\xba\xf5' >>> '知乎' #這個地方的編碼被power shelll本身處理了 '\xd6\xaa\xba\xf5' # sublime 3 REPL python >>> u'知乎' u'\u77e5\u4e4e' >>> u'知乎'.encode('utf-8') '\xe7\x9f\xa5\xe4\xb9\x8e' >>> u'知乎'.encode('gbk') '\xd6\xaa\xba\xf5' >>> '知乎' #這個地方的編碼被REPL本身處理了 '\xe7\x9f\xa5\xe4\xb9\x8e'
在上面兩個例子的最後一行,能夠看出在不一樣的shell下,這兩個漢字的說明在解釋器解釋這個漢字字符串的時候是不一樣的。這個問題在stackoverflow,上有很好的解釋。web
在進一步進行解釋前,須要對 python
中的 ''
和 u''
進行詳細的解釋,在這個例子中咱們就以 鐭ヤ箮
這個詞來進行解釋。shell
#windows 10 powershell >>>import sys >>>sys.stdout.encoding 'cp936' >>>'a' 'a' >>>'鐭ヤ箮' '\xe7\x9f\xa5\xe4\xb9\x8e' >>> u'鐭ヤ箮' u'\u942d\u30e4\u7bae' >>>u'\u942d\u30e4\u7bae'.encode('ascii') Traceback (most recent call last): File "<stdin>", line 1, in <module> UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-2: ordinal not in range(128) >>>u'\u0047'.encode('ascii') G
上面的這個例子,若是仔細思考的話,是能夠引伸出不少問題的。windows
第一個問題,漢字這個漢字是如何顯示到屏幕上的,解釋器又是如何處理這個漢字的,才使得最後解析出來的是一個點陣獲取碼。首先不管是怎樣的方式輸出的漢字(複製粘貼也好,直接用輸入法也好),機器最終都是以點陣獲取碼(就是一段特殊的16進制數字)的形式去調用所擁有的點陣庫,點陣庫中的每個漢字有他本身的特殊的點陣方式。固然這裏的是點陣字庫而不是矢量字庫。瀏覽器
第二個問題是若是說python2
中默認的編碼方式是ascii
,那麼非英文字符按理來講是不能編碼的 呀(由於ascii
中只有英文字符)。其實這個說法自己是沒有錯的,而非英文字符仍是要顯示的,這個時候python
就對這些非英文字符進行了不規範的處理,它會使用sys.stdout.encoding
所顯示的編碼方案對當前顯示的漢字進行編碼,而後將這個漢字編碼後的存儲碼輸出而來。websocket
第三個問題是 u''
進行了什麼樣的處理。這個問題和第二個問題仍是頗有聯繫的,首先 u''
在 python2
中表示的是對應字符的 unicode
碼的形式,至於過程,則是使用當前的終端的編碼方案對字符進行(decode
)解碼,而後再將解碼後的所對應的 unicode
碼顯示出來。也就是說,u''
這種形式,其實已經對字符進行了解碼,因此若是採用 ascii
這種編碼方案對超出編碼範圍的字符進行編碼的話,是會出現上面所示的錯誤的。socket
#the code below is under a file.py #coding: utf-8 import sys ed = sys.stdout.encoding print '知乎'.decode('utf-8').encode(ed)
在進度1中,對python解釋器對"", u""
進行了比較詳細的解釋,我想大概也能解釋了爲何有時候即便在文件頭又coding:xxx
這樣的聲明仍是會出現各類各樣的亂碼。之因此會出現這樣的亂碼是由於在不一樣的終端下,ed
是不同的,而文件的編碼保存方式卻又是固定的,我以爲這樣的設計不能說壞,可是至少如今來看確實不算是好的設計,在python3
中到是在這方面進行了很大程度的改進,我以爲在這方面實現起來確實還不錯。post
回到話題,上面的這個文件,不管你在哪一個平臺下運行他都會呈現它本來的漢字。相反若是用下面這個樣子的東西去測試,你也許就會發現所出出現的問題了。測試
print '知乎'
python2的編碼問題其實早已經出現很久,一開始我只是解決了亂碼的問題,後來在各類終端下測試的時候,發現了這樣那樣的問題,我以爲這真的仍是蠻胃疼的,每次都得直接google錯誤,真的不是一個長久之計,遂花時間研究了一下編碼。每次從新研究一次,老是會獲得新的體驗。
編碼這個範疇真的仍是蠻大的,有幸能在早期糾結於此。
這樣的聲明#coding: utf-8的意義,於此。
This PEP proposes to introduce a syntax to declare the encoding of
a Python source file. The encoding information is then used by the Python parser to interpret the file using the given encoding. Most notably this enhances the interpretation of Unicode literals in the source code and makes it possible to write Unicode literals using e.g. UTF-8 directly in an Unicode aware editor.