原本是隻打算寫一篇關於中文亂碼的blog的,可是發現要講的東西跨度有點大,很差寫到同一篇裏面,因此分開了。html
另外一篇是 《【原創】通俗易懂地解決中文亂碼問題(2) --- 分析解決Mysql插入移動端表情符報錯 ‘incorrect string value: '\xF0...》 。java
這一篇重點在編碼的理論,另外一篇重點在解決問題及思路。sql
1、問題的開始windows
中文亂碼問題常常出如今實際工程中,尤爲容易發生在經驗不足的團隊對問題預估不足的狀況下。網站開發,社交聊天等對輸入信息不可控的應用每每是重災區。再加上移動互聯網的火熱,新興字符和表情也開始頻繁被使用,若是不能達到足夠的支持,對用戶體驗來講是個災難。因此,在設計系統的開始,要嚴格把控字符編碼。以大致明確怎麼作是不會出錯的(嚴格按規則限制每每難以把控,而且容易漏掉被鑽空子,因此作到不出錯是出發點)。數組
2、Unicode瀏覽器
Unicode是本文的重點。post
Unicode是一種通用字符集,是對字符的定義。和之對應的也有,好比 ISO 8859-1。但Unicode被普遍使用併成爲業界的標準,因此咱們能夠認爲Unicode就是對計算機裏字符的定義,在內存中的表現是0,1串。字體
並且,Unicode的編碼很乾淨,它爲 字符而非字形定義惟一的代碼。換句話說,統一碼以一種抽象的方式(即數字)來處理字符,並將視覺上的演繹工做(例如字體大小、外觀形狀、字體形態、文體等)留給其餘軟件來處理,例如網頁瀏覽器或是文字處理器。舉個例子,如 「ɑ/a」、「強/強」、「戶/戶/戸」。(引自wiki)網站
這樣,Unicode自己要作的任務很明確,就是合適的擴充編碼。編碼
3、UTF-8
UTF-8是Unicode的一種實現方式,是可變長的字符編碼。與之對應的還有GBK(固定長度),Latin,UTF-16(Unicode的徹底式)等等。
這些爲何是實現方式呢?不是Unicode已經定義好了嗎?其實這也是計算機學科常常用的方法,這些不一樣的編碼就相似於針對Unicode的各類trick。
舉個簡單的例子,一個整形數組A[],那麼給A[]排序這個定義就至關於Unicode。那麼是採用快排、堆排仍是歸併,用正序仍是倒序排列結果,這些方法就相當於編碼格式。而這些都是對這個定義的具體實現過程,可是方法不一樣。
所以,不管是UTF-八、GBK、Latin等,其還原的編碼結果都是同一個Unicode編碼。
4、Unicode和UTF-8的關係及轉換過程
那麼對於Unicode和UTF-8的關係,能夠用上面的例子理解。不過真實狀況應該是相似下面這樣的。
好比"國"字的Unicode編碼定義爲 00000000 00000000 00110100 11000000 (假設)。
因爲其低16位都是0,爲了減小存儲和傳輸這個字在字節上的浪費,就選擇高16位來表示。同時因爲UTF-8是可變長的,因此須要標識位來標識這個編碼到底使用了幾個字節。
因此 「國」字 對應的 UTF-8的編碼應該是 11100011 10010011 10000000(加粗的是原編碼的高16位)。
轉換公式:1110xxxx(E0-EF) 10yyyyyy 10zzzzzz,顯示標明的是標誌位)。
如下附上UTF-8的編碼方式:(引自wiki)
5、中文跨平臺亂碼及解決辦法
有了以上知識的積累,咱們能夠分析爲何跨平臺會出現亂碼?明明好好的Unicode怎麼就亂了呢?
那麼很直觀咱們會想到應該是編碼格式不兼容。
對於windows平臺,編碼格式是GBK,對應的漢字是兩個字節長度。對於Linux平臺,編碼格式是UTF-8,對應的漢字是3個字節。(這裏都是默認狀況)
那麼咱們還用上面 排序這個例子來解釋。
好比如今Unicode用 {1,2,3}定義,GBK表明正序排列,UTF-8表明倒序排列。那麼如今Unicode在GBK下的編碼是{1,2,3},在UTF-8下的編碼是{3,2,1}。
如今由GBK編碼還原Unicode編碼,那麼正向解析GBK就是Unicode。而由UTF-8編碼還原Unicode編碼,須要逆向解析UTF-8編碼。這都是和自身對應的。
可是若是一個把GBK編碼誤認爲是UTF-8,那麼逆向解析後的結果是{3,2,1}。首先這個結果不是原始的Unicode編碼,那麼其轉換的結果不是咱們須要的。其次,極可能這個編碼結果在Unicode中尚未定義,可能會出現相似空格同樣的空白符。
所以這就是跨平臺中文亂碼的緣由,編碼和解碼方式出現了差異。
解決辦法:
解決辦法其實有不少種,根據自身應用的不一樣既能夠選擇在代碼端進行編碼的轉換(好比java的 String str = new String(str.getBytes("GBK"), "UTF-8");),也能夠在輸入端進行編碼格式的調整。
不過歸結下來只有一點,即 若是當前輸入是GBK編碼,而你須要的又是UTF-8編碼,那麼:
1. 用GBK的解碼方式轉換成Unicode。
2. 使用UTF-8編碼進行編碼。
6、中文編碼一些有趣的應用
這裏我只想到了war3(感謝@殭屍的提醒)上面一些搞笑的名字(一不當心貌似暴露了什麼。。),後面想到其它還會更新的。
好比下面這個圖:
藍圈裏面的玩家名字是正常顯示的,爲綠色。紅圈裏面的是藍色,至關於突破了war3的限制顯示了其它特殊顏色。
這個作法就是對應名字後面加上|r。這是一個轉義符,合理的利用了war3給用戶開放的字符集併產生了特殊效果。因此這也是我開篇說的嚴格把控字符集是很難的,控制到不出錯(好比系統亂碼)已經挺好了。
轉載請註明出處,謝謝~ http://www.cnblogs.com/xiaoboCSer/p/4175361.html