在Vim中,有四個與編碼有關的選項:fileencodings
、fileencoding、
encoding
和termencoding
。實際使用中,任何一個選項錯誤,都會導致亂碼。因此, 每一個 Vim 使用者都應該明確這四個選項的含義。
1. encoding
encoding
是 Vim 內部使用的字元編碼方式。 設定了 encoding
後, Vim 內所有的 buffer、 寄存器、 指令碼中的字串等, 全都使用這個編碼。 Vim 在工作的時候, 如果編碼方式與它的內部編碼不一致, 它會先把編碼轉換成內部編碼。 如果工作用的編碼中含有無法轉換為內部編碼的字元, 在這些字元就會丟失。 因此,在選擇 Vim 的內部編碼的時候, 一定要使用一種表現能力足夠強的編碼, 以免影響正常工作。
由於 encoding
選項涉及到 Vim 中所有字元的內部表示, 只能在 Vim 啟動時設定一次, 在 Vim 工作過程中修改 encoding
會造成許多問題。 如果沒有特殊理由, 請始終將 encoding
設定為 utf-8
。 為了避免在非 UTF-8 的系統如 Windows 下, 菜單和系統提示出現亂碼, 可同時做這幾項設定:
set encoding=utf-8
set langmenu=zh_CN.UTF-8
language message zh_CN.UTF-8
2. termencoding
termencoding
是 Vim 用於螢幕顯示的編碼, 顯示時Vim 會先把內部編碼轉換為螢幕編碼再輸出。 內部編碼中含有無法轉換為螢幕編碼的字元時, 該字元會變成問號, 但不會影響對它的編輯操作。 如果 termencoding
沒有設定, 則直接使用 encoding
不進行轉換。
舉例:當你在 Windows 下通過 telnet 登入 Linux 時, 由於 Windows 的 telnet 是 GBK 編碼的, 而 Linux 下用 UTF-8 編碼, 你在 telnet 下的 Vim 中就會出現亂碼。 有兩種方式解決此問題: 一是把 Vim 的 encoding
改為 gbk
, 另一種方法是保持 encoding
為 utf-8
, 把 termencoding
改為 gbk
, 讓 Vim 在顯示時轉碼。 使用前一種方法時, 如果遇到編輯的檔案中含有 GBK 無法表示的字元時, 這些字元就會丟失; 而使用後一種方法, 雖然由於終端所限, 這些字元無法顯示, 但在編輯過程中這些字元是不會丟失的。
對於圖形介面下的 GVim, 它的顯示不依賴 TERM, 因此 termencoding
對於它沒有意義。 在 GTK2 下的 GVim 中, termencoding
永遠是 utf-8
, 並且不能修改,而 Windows 下的 GVim 則忽略 termencoding
的存在。
3. fileencoding
當 Vim 從磁碟上讀取檔案時, 會對檔案的編碼進行探測。 如果檔案的編碼方式和 Vim 的內部編碼方式不同, Vim 就會對編碼進行轉換,轉換完畢後Vim 會將 fileencoding
選項設定為檔案的編碼;當 Vim 存檔時, 如果 encoding
和 fileencoding
不一樣, Vim 就會進行編碼轉換。 因此, 通過開啟檔案後設定 fileencoding
, 可以將檔案由一種編碼轉換為另一種編碼。 但是, 由前面的介紹可以看出, fileencoding
是在開啟檔案的時候, 由 Vim 進行探測後自動化佈建的。 因此, 如果出現亂碼, 我們無法通過在開啟檔案後重新設定 fileencoding
來糾正亂碼。
4. fileencodings
編碼的自動識別是通過設定 fileencodings 實現的, 注意是複數形式。 fileencodings 是一個用逗號分隔的列表, 列表中的每一項是一種編碼的名稱。 當開啟檔案時, Vim 按順序使用 fileencodings 中的編碼進行嘗試解碼, 如果成功就使用該編碼方式進行解碼, 並將 fileencoding
設定為這個值, 如果失敗就繼續實驗下一個編碼。因此設定 fileencodings
時, 一定要把要求嚴格的、 當檔案不是這個編碼的時候更容易出現解碼失敗的編碼方式放在前面, 把寬鬆的編碼方式放在後面。
例如, latin1 是一種非常寬鬆的編碼方式, 任何一種編碼方式得到的文本, 用 latin1 進行解碼, 都不會發生解碼失敗,當然解碼得到的結果自然也就是理所當然的“亂碼”。 因此, 如果你把 latin1
放到了 fileencodings
的第一位的話, 開啟任何中文檔案都是亂碼也就是理所當然的了。
以下是滇狐推薦的一個 fileencodings
設定:
set fileencodings=ucs-bom,utf-8,cp936,gb18030,big5,euc-jp,euc-kr,latin1
其中, ucs-bom 是一種非常嚴格的編碼, 非該編碼的檔案幾乎沒有可能被誤判為 ucs-bom, 因此放在第一位;utf-8 也相當嚴格, 除了很短的檔案外 (例如GBK 編碼的“聯通”被誤判為 UTF-8 編碼的經典錯誤), 現實中一般檔案是幾乎不可能被誤判的, 因此放在第二位;接下來是 cp936 和 gb18030, 這兩種編碼相對寬鬆, 如果放前面會出現大量誤判, 就讓它們靠後一些;cp936 的編碼空間比 gb18030 小, 所以把 cp936 放在 gb18030 前面;至於 big5、euc-jp 和 euc-kr, 它們的嚴格程度和 cp936 差不多, 把它們放在後面, 在編輯這些編碼的檔案的時候必然出現大量誤判, 但這是 Vim 內建編碼探測機制沒有辦法解決的事。 由於中國使用者很少有機會編輯這些編碼的檔案, 因此我們還是決定把 cp936 和 gb18030 前提以保證這些編碼的識別;最後就是 latin1 了,它是一種極其寬鬆的編碼, 以至於我們不得不把它放在最後一位。 不過可惜的是, 當你碰到一個真的 latin1 編碼的檔案時, 絕大部分情況下, 它沒有機會 fall-back 到 latin1, 往往在前面的編碼中就被誤判了。 不過, 正如前面所說的, 中國使用者沒有太多機會接觸這樣的檔案。
如果編碼被誤判了, 解碼後的結果就無法被人類識別, 於是我們就說, 這個檔案亂碼了。 此時, 如果你知道這個檔案的正確編碼的話, 可以在開啟檔案的時候使用 ++enc=encoding
的方式來開啟檔案, 如:
:e ++enc=utf-8 myfile.txt
5. fencview
根據前面的介紹, 我們知道,通過 Vim 內建的編碼識別機制, 識別率是很低的, 尤其是對於簡體中文 (GBK/GB18030)、 繁體中文 (Big5)、 日文 (euc-jp) 和韓文 (euc-kr) 之間的識別。 而對於普通使用者而言, 肉眼看出一個檔案的編碼方式也是很不現實的事情。 因此,強烈推薦水木社區的 mbbill 開發的 fencview 外掛程式,該外掛程式使用詞頻統計的方式識別編碼, 正確率非常高。 點擊 這裡 下載。