VIM字符編碼基礎知識

1 字符編碼基礎知識vim

字符編碼是計算機技術中最基本和最重要的知識之一。若是缺少相關知識,請自行惡補之。這裏僅作最簡要的說明。網絡

1.1 字符編碼概述性能

所謂的字符編碼,就是對人類發明的每個文字進行數字化表示。最經典的ASCII編碼就是西方人發明的針對英文字符的編碼方法,包括26個英文字母、數字、標點、特殊字符等。問題是,這種編碼的範圍是0-127,只能對128個字符進行編碼。當計算機來到其餘國家後發現,除了英語,還有大量的其餘語言,並且涵蓋的字符也遠遠多於128個。爲此,各個國家開始針對本身的語言進行編碼工做,例如中國的GBK,日本的CJK,等等。學習

這雖然解決了ASCII編碼不夠用的問題,可是卻帶來了另一個更加嚴重的問題。那就是各個國家的字符編碼不統一,致使沒法進行統一處理。因而乎,著名的UNICODE出現了,UNICODE編碼範圍很是大,能夠涵蓋全球全部語言的字符。測試

1.2 區分字符集(Charset)和字符編碼(Char Encoding)字體

這兩個術語有時候不進行區分的使用,可是理解其區別對於理解字符編碼相當重要。編碼

代碼點(Code Point)
也就是咱們前面說到的,爲每個字符分配一個數字序號。例如在ASCII字符集中,字符A被分配成65號,那就是說A的代碼點是65。一種編碼規範中,全部的代碼點的集合就是字符集。操作系統

字符編碼
字符編碼是代碼點的二進制存儲格式。仍是前面的例子,在ASCII字符集中,A的代碼點是65。而這個65到底是怎麼用二進制0和1序列表示呢?這就是字符編碼的工做。在ASCII編碼中,這個65被存儲爲01000001,一共佔據一個字節(8個二進制位)。.net

說到這裏也許你會以爲,這中區別也沒什麼啊,這主要是由於在咱們的例子中ASCII字符集的代碼點只有一種字符編碼方式,也就是ASCII字符編碼。而這在其餘字符集中卻不老是這樣,例如UNICODE字符集。blog

UNICODE字符集,規定了全球每個字符的代碼點,例如英文字母A在UNICODE字符集中的代碼點是65(哈哈,這個代碼點與ASCII是兼容的),然而65的存放格式卻有不少方式:例如在UTF-8字符編碼規範中被存儲爲8個二進制位:01000001,而在UCS-16中被存儲爲16個二進制位:0000000001000001,而在UCS-32中被存儲爲32個二進制位:00000000000000000000000001000001。

說到這裏,就明白了,UNICODE字符集對應有不少不一樣的字符編碼方式:UTF-8,UCS-16,UCS-32等等。
而ASCII字符集只有一種編碼方式:ASCII字符編碼。

UNICODE字符集的不一樣編碼方式是爲了適應不一樣的環境而被創造出來的,例如UTF-8被用來網絡傳輸,文件存放,UCS-16則被用來做爲內存中的存放方式,以利於快速統一計算。

現現在,雖然UNICODE字符集已經得到普遍採用,然而歷史遺留的其餘字符集仍大量存在。
近年來,字符集的概念不多被說起,字符編碼則更多的被使用。

1.3 字符編碼與顯示

對字符進行編碼只是完成了存放、處理和傳輸,要想把字符的形狀繪製出來,還要有對應的字體以及渲染手段。

對於GUI程序,操做系統都會提供API來對指定字符進行渲染繪製。對於終端來講,終端有一個字符編碼的屬性,從而把接收到的二進制字節流按照這個字符編碼進行解析,而後調用相應的渲染引擎來對其進行顯示,詳情請參考個人一篇博文:從調用printf()到顯示器上看到字符串。

2 VIM讀取、顯示、保存文本文件過程分析

2.1 VIM涉及到的字符編碼

(1) 磁盤文件的字符編碼
存放在磁盤上的文本文件,是按照必定的字符編碼進行保存的,不一樣的文件可能使用了不一樣的字符編碼。
這在VIM中被叫作:fileencoding。

(2) VIM緩衝區以及界面的字符編碼
VIM運行時,其菜單、標籤、以及各個緩衝區統一使用一種字符編碼方式。
這在VIM中被叫作:encoding。

(3) 終端使用的字符編碼
終端同一時刻只能使用一種字符編碼,並按照這種編碼從接收到的字節流中識別字符,並顯示,終端的字符編碼是能夠動態調整的。
這在VIM中被叫作:termencoding。

2.2 vim讀、顯、存分析

(1)讀文件
VIM打開文件時,並不知道文件的字符編碼,因此不得不進行探測。探測是按照必定的優先順序進行測試。依據的標準就是:fileencodings。VIM逐一測試fileencodings變量指定的字符編碼方式,直到找到認爲合適的而後把這種字符編碼方式設置爲fileencoding變量。

而後把文件中的編碼轉換成encoding指定的編碼方式,存入文件緩衝區中。
(2)顯示文件
vim把文件讀取完畢並以encoding編碼存放到緩衝區內存以後,會根據termencoding指定的終端編碼方式,轉換成termencoding編碼後,寫入到終端。此時,終端按照自身的編碼屬性識別出一個個的字符,調用渲染引擎繪製到屏幕上。

(3)保存文件
VIM把緩衝區中的encoding編碼的字節集合轉換成fileencoding編碼後寫入磁盤,完成文件保存。

能夠看出,VIM涉及到的3種字符編碼之間的轉換:
讀:fileencoding—–> encoding
顯:encoding ——> termencoding
寫:encoding ——-> fileencoding

只要這三種轉換都不會出現問題,那麼VIM就能夠正常工做,不會出現亂碼。
然而,並非全部的字符編碼之間都可以無損轉換,例如GBK字符編碼轉換爲ASCII編碼時,因爲ASCII並不能徹底包含GBK的字符,因此會出現問題。

3 常見亂碼狀況分析

3.1 讀文件時,VIM探測fileencoding不許確

這很好理解,好比以GBK編碼方式存儲的文件,VIM把fileencoding探測成了ASCII,則確定會出現問題。

【解決方法】一是靠VIM自身提升探測水平;二是設置合適的fileencodings變量,把最可能用到的編碼方式放到最前面。若是VIM實在是探測不對,那麼就只能經過 :set fileencoding=xxx 命令來手動探測了。

3.2 fileencoding編碼沒法正確轉換到encoding編碼

例如,文件採用GBK編碼,而ecoding使用ASCII,這樣大量的漢字字符沒法被轉換,從而致使亂碼。
【解決方法】把encoding設置成UTF-8,目前爲止UTF-8能包含全部字符,因此其餘的任何編碼方式均可以無損的轉換爲UTF-8。

3.3 encoding沒法正確轉換到termencoding

這個問題,與3.2相似。
【解決辦法】把termencoding設置爲什麼encoding相同。默認termencoding=」「的狀況下,這二者就是相同的。

3.3 termencoding與實際的終端字符編碼不一致

例如原本字符終端的編碼屬性爲GBK,而termencoding卻爲UTF-8,那麼VIM就會錯誤的認爲終端就是UTF-8編碼的,致使向終端輸出UTF-8編碼的字節流,而終端卻按照GBK來識別,固然就會識別成亂碼。
【解決辦法】把終端實際的編碼方式和VIM的termencoding統一塊兒來。

3.4 終端顯示能力欠缺

例如,傳統的字符終端,自己不具有顯示漢字的能力,雖然它能夠識別出UTF-8編碼的漢字,可是渲染引擎沒法正確繪製,也就顯示成了亂碼。
【解決辦法】儘可能仍是使用Putty等僞終端軟件,避免直接使用字符終端設備;若是實在不能避免,就要避免使用ASCII字符集之外的字符,好好學習英文吧。

4 杜絕亂碼的最佳實踐

全部編碼通通設置爲utf-8。這樣既可以識別人類全部語言,又避免了各類編碼之間轉換的性能損失。

4.1 VIM設置

set encoding=utf-8
set termencoding=utf-8
set fileencodings=utf-8,gbk,latin1

若是無特殊要求和限制,磁盤文件也以UTF-8方式存儲。

set fileencoding=utf-8

轉自:http://blog.csdn.net/smstong/article/details/51279810

相關文章
相關標籤/搜索