編碼(轉)

https://www.zhihu.com/question/28164512java

關於編碼和亂碼的問題,我簡單講一下。python

一般問這類問題的人是混淆了若干個不一樣的概念,而且他們本身也沒有意識到本身混淆了這些概念的。linux

  1. 終端顯示字符的編碼(windows下終端是cmd,linux下是各類terminal,遠程登陸是putty或者xshell)
  2. shell環境的編碼。好比中文版windows用的是gbk(向下兼容gb2312),大多數linux發行版使用的是utf-8(LANG=zh_CN.UTF-8)。
  3. 文本文件的編碼。這個一般取決於你的編輯器,並且有的編輯器支持多種編碼的話,你能夠在文本開頭位置指定編輯器使用特定編碼。好比# -*- coding: utf8 -*-,vim看到這行會默認將這個腳本認定爲utf-8兼容編碼格式。
  4. 應用程序的內部編碼。一個字符串,做爲數據只是一個字節數組,可是做爲字符的數組,就有一個解析方式。java和python的內部字符編碼是utf-16,python和java都支持用不一樣的編碼來對字節數組進行decode來獲得字符數組。

 

拿題主的問題來解釋一下。shell

我在ubuntu kylin中文環境下默認terminal中作了一樣的實驗,可是結果和題主剛好相反:ubuntu

看見沒有?vim

題主和我都沒有說謊,這是爲何呢?
由於windows

unicode("漢字","gb2312")

這坨代碼的含義其實是:將這裏顯示的這坨看上去像「漢字」的東西,用gb2312解碼,轉換爲unicode字符串。unicode("漢字","utf-8")相似,只不過是用utf-8解碼,轉成unicode字符串。
(注:這裏涉及到兩個概念——unicode字符集和utf-8編碼——不少時候會用混淆,一個字符集表示一堆符號,而一種編碼是用二進制表示這個字符集的一種編碼方式。一樣是unicode字符集,能夠有utf-八、utf-1六、utf-32等等編碼方式。)數組

那這裏顯示的看上去像「漢字」的,tmd的究竟是個什麼東西?編輯器

    1. 若是是在個人環境下,也就是linux utf-8環境下一個utf-8顯示終端,能顯示成「漢字」的這坨東西,它其實是以utf-8編碼的「漢」字和「字」字兩個unicode字符。它們的真實字符值就是u'\u6c49\u5b57'(內碼),能夠用"漢字".encode("hex")來查看當前終端下(utf-8編碼值)的十六進制碼。
      1. 。因此個人命令是,將'e6b189e5ad97'這坨字節數組,轉換爲unicode的字符數組。——結果毫無難度,沒有錯誤,由於它原本就是utf-8編碼,因此可以正常做爲unicode字符解碼。
        可是unicode("漢字", "gb2312")就不同了,這個命令等同於「將'e6b189e5ad97'這坨東西,用gb2312編碼方式來解碼成字符」,可是實際上因爲編碼空間並不兼容,使用gb2312編碼方式沒法解碼這麼一坨奇葩的數據,因此葛屁了。
      2. 在題主的環境下,由於系統終端和默認文件編碼都是GBK,因此這個數其實是

      3. 這個其實是gbk(兼容gb2312)的字符「漢字」的真實字節數組。
        因此對這坨數據作unicode("漢字","utf8")會失敗——由於無論你怎麼想,雖然看上去是同樣,可是實際上不是同一坨東西啊!
      4. 題主如今弄了一個文件,在開始加上了
        # -*- coding: utf8 -*-
        這下編輯器看到了,知道這文件是utf-8的了。因此編輯器對讀入的一坨坨字節用utf-8來解碼,對於輸出到磁盤的漢字也用utf-8來編碼。因此你在文件裏面看到的看上去像「漢字」的東西,就和第一種狀況下想同了,固然代碼就跑得通。
        順便說一下,若是編輯器無視行首這行編碼聲明,或者編輯器沒法支持utf-8格式,那麼你弄好的文件在那個編輯器下就會顯示亂碼,多麼簡單的道理啊。

      因此,要可以正常的顯示中文(或者其餘什麼亂七八糟奇葩的多字節文字),如下條件缺一不可:
      1. 終端和環境的編碼一致(本機一般是一致的,不一致經常出如今遠程登陸);若是不一致就須要有編輯器或者文本閱讀器作一個兼容二者的轉換。
      2. 編輯器可以認識文本編碼
      3. 系統擁有能顯示這種字符的字體。

      這也就是我爲何一直反對在程序文本中使用除ascii以外的全部編碼字符的緣由。環境太複雜了,繞開問題遠比解決問題輕鬆。字體

相關文章
相關標籤/搜索