#TITLE: VIM 文件編碼識(shí)別與亂碼處理
edyfox
在 Vim 中,
有四個(gè)與編碼有關(guān)的選項(xiàng),
它們是:
''fileencodings''、
''fileencoding''、
''encoding'' 和 ''termencoding''。
在實(shí)際使用中,
任何一個(gè)選項(xiàng)出現(xiàn)錯(cuò)誤,
都會(huì)導(dǎo)致出現(xiàn)亂碼。
因此,
每一個(gè) Vim 用戶都應(yīng)該明確這四個(gè)選項(xiàng)的含義。
下面,
我們?cè)敿?xì)介紹一下這四個(gè)選項(xiàng)的含義和作用。
* encoding
''encoding'' 是 Vim 內(nèi)部使用的字符編碼方式。
當(dāng)我們?cè)O(shè)置了 ''encoding'' 之后,
Vim 內(nèi)部所有的 buffer、
寄存器、
腳本中的字符串等,
全都使用這個(gè)編碼。
Vim 在工作的時(shí)候,
如果編碼方式與它的內(nèi)部編碼不一致,
它會(huì)先把編碼轉(zhuǎn)換成內(nèi)部編碼。
如果工作用的編碼中含有無(wú)法轉(zhuǎn)換為內(nèi)部編碼的字符,
在這些字符就會(huì)丟失。
因此,在選擇 Vim 的內(nèi)部編碼的時(shí)候,
一定要使用一種表現(xiàn)能力足夠強(qiáng)的編碼,
以免影響正常工作。
由于 ''encoding'' 選項(xiàng)涉及到 Vim 中所有字符的內(nèi)部表示,
因此只能在 Vim 啟動(dòng)的時(shí)候設(shè)置一次。
在 Vim 工作過(guò)程中修改 ''encoding'' 會(huì)造成非常多的問(wèn)題。
如果沒有特別的理由,
請(qǐng)始終將 ''encoding'' 設(shè)置為 ''utf-8''。
為了避免在非 UTF-8 的系統(tǒng)如 Windows 下,
菜單和系統(tǒng)提示出現(xiàn)亂碼,
可同時(shí)做這幾項(xiàng)設(shè)置:
#Code syntax="
vim"
<
<
---
set encoding=utf-8
set langmenu=zh_CN.UTF-8
language message zh_CN.UTF-8
* termencoding
''termencoding'' 是 Vim 用于屏幕顯示的編碼,
在顯示的時(shí)候,
Vim 會(huì)把內(nèi)部編碼轉(zhuǎn)換為屏幕編碼,
再用于輸出。
內(nèi)部編碼中含有無(wú)法轉(zhuǎn)換為屏幕編碼的字符時(shí),
該字符會(huì)變成問(wèn)號(hào),
但不會(huì)影響對(duì)它的編輯操作。
如果 ''termencoding'' 沒有設(shè)置,
則直接使用 ''encoding'' 不進(jìn)行轉(zhuǎn)換。
舉個(gè)例子,
當(dāng)你在 Windows 下通過(guò) telnet 登錄 Linux 工作站時(shí),
由于 Windows 的 telnet 是 GBK 編碼的,
而 Linux 下使用 UTF-8 編碼,
你在 telnet 下的 Vim 中就會(huì)亂碼。
此時(shí)有兩種消除亂碼的方式:
一是把 Vim 的 ''encoding'' 改為 ''gbk'',
另一種方法是保持 ''encoding'' 為 ''utf-8'',
把 ''termencoding'' 改為 ''gbk'',
讓 Vim 在顯示的時(shí)候轉(zhuǎn)碼。
顯然,
使用前一種方法時(shí),
如果遇到編輯的文件中含有 GBK 無(wú)法表示的字符時(shí),
這些字符就會(huì)丟失。
但如果使用后一種方法,
雖然由于終端所限,
這些字符無(wú)法顯示,
但在編輯過(guò)程中這些字符是不會(huì)丟失的。
對(duì)于圖形界面下的 GVim,
它的顯示不依賴 TERM,
因此 ''termencoding'' 對(duì)于它沒有意義。
在 GTK2 下的 GVim 中,
''termencoding'' 永遠(yuǎn)是 ''utf-8'',
并且不能修改。
而 Windows 下的 GVim 則忽略 ''termencoding'' 的存在。
* fileencoding
當(dāng) Vim 從磁盤上讀取文件的時(shí)候,
會(huì)對(duì)文件的編碼進(jìn)行探測(cè)。
如果文件的編碼方式和 Vim 的內(nèi)部編碼方式不同,
Vim 就會(huì)對(duì)編碼進(jìn)行轉(zhuǎn)換。
轉(zhuǎn)換完畢后,
Vim 會(huì)將 ''fileencoding'' 選項(xiàng)設(shè)置為文件的編碼。
當(dāng) Vim 存盤的時(shí)候,
如果 ''encoding'' 和 ''fileencoding'' 不一樣,
Vim 就會(huì)進(jìn)行編碼轉(zhuǎn)換。
因此,
通過(guò)打開文件后設(shè)置 ''fileencoding'',
我們可以將文件由一種編碼轉(zhuǎn)換為另一種編碼。
但是,
由前面的介紹可以看出,
''fileencoding'' 是在打開文件的時(shí)候,
由 Vim 進(jìn)行探測(cè)后自動(dòng)設(shè)置的。
因此,
如果出現(xiàn)亂碼,
我們無(wú)法通過(guò)在打開文件后重新設(shè)置 ''fileencoding'' 來(lái)糾正亂碼。
* fileencodings
編碼的自動(dòng)識(shí)別是通過(guò)設(shè)置 fileencodings 實(shí)現(xiàn)的,
注意是復(fù)數(shù)形式。
fileencodings 是一個(gè)用逗號(hào)分隔的列表,
列表中的每一項(xiàng)是一種編碼的名稱。
當(dāng)我們打開文件的時(shí)候,
VIM 按順序使用 fileencodings 中的編碼進(jìn)行嘗試解碼,
如果成功的話,
就使用該編碼方式進(jìn)行解碼,
并將 ''fileencoding'' 設(shè)置為這個(gè)值,
如果失敗的話,
就繼續(xù)試驗(yàn)下一個(gè)編碼。
因此,
我們?cè)谠O(shè)置 ''fileencodings'' 的時(shí)候,
一定要把要求嚴(yán)格的、
當(dāng)文件不是這個(gè)編碼的時(shí)候更容易出現(xiàn)解碼失敗的編碼方式放在前面,
把寬松的編碼方式放在后面。
例如,
latin1 是一種非常寬松的編碼方式,
任何一種編碼方式得到的文本,
用 latin1 進(jìn)行解碼,
都不會(huì)發(fā)生解碼失敗
--
當(dāng)然,
解碼得到的結(jié)果自然也就是理所當(dāng)然的“亂碼”。
因此,
如果你把 ''latin1'' 放到了 ''fileencodings'' 的第一位的話,
打開任何中文文件都是亂碼也就是理所當(dāng)然的了。
以下是滇狐推薦的一個(gè) ''fileencodings'' 設(shè)置:
#Code syntax="
vim"
<
<
---
set
fileencodings=ucs-bom,utf-8,cp936,gb18030,big5,euc-jp,euc-kr,latin1
---
其中,
ucs-bom 是一種非常嚴(yán)格的編碼,
非該編碼的文件幾乎沒有可能被誤判為 ucs-bom,
因此放在第一位。
utf-8 也相當(dāng)嚴(yán)格,
除了很短的文件外
(例如許多人津津樂(lè)道的 GBK 編碼的“聯(lián)通”被誤判為 UTF-8 編碼的經(jīng)典錯(cuò)誤),
現(xiàn)實(shí)生活中一般文件是幾乎不可能被誤判的,
因此放在第二位。
接下來(lái)是 cp936 和 gb18030,
這兩種編碼相對(duì)寬松,
如果放前面的話,
會(huì)出現(xiàn)大量誤判,
所以就讓它們靠后一些。
cp936 的編碼空間比 gb18030 小,
所以把 cp936 放在 gb18030 前面。
至于 big5、euc-jp 和 euc-kr,
它們的嚴(yán)格程度和 cp936 差不多,
把它們放在后面,
在編輯這些編碼的文件的時(shí)候必然出現(xiàn)大量誤判,
但這是 Vim 內(nèi)置編碼探測(cè)機(jī)制沒有辦法解決的事。
由于中國(guó)用戶很少有機(jī)會(huì)編輯這些編碼的文件,
因此我們還是決定把 cp936 和 gb18030 前提以保證這些編碼的識(shí)別。
最后就是 latin1 了。
它是一種極其寬松的編碼,
以至于我們不得不把它放在最后一位。
不過(guò)可惜的是,
當(dāng)你碰到一個(gè)真的 latin1 編碼的文件時(shí),
絕大部分情況下,
它沒有機(jī)會(huì) fall-back 到 latin1,
往往在前面的編碼中就被誤判了。
不過(guò),
正如前面所說(shuō)的,
中國(guó)用戶沒有太多機(jī)會(huì)接觸這樣的文件。
如果編碼被誤判了,
解碼后的結(jié)果就無(wú)法被人類識(shí)別,
于是我們就說(shuō),
這個(gè)文件亂碼了。
此時(shí),
如果你知道這個(gè)文件的正確編碼的話,
可以把 ''fileencodings'' 改成只有這一種編碼,
阻止任何 fall-back 發(fā)生,
然后重新打開這個(gè)文件。
* fencview
根據(jù)前面的介紹,
我們知道,
通過(guò) Vim 內(nèi)置的編碼識(shí)別機(jī)制,
識(shí)別率是很低的,
尤其是對(duì)于簡(jiǎn)體中文 (GBK/GB18030)、
繁體中文 (Big5)、
日文 (euc-jp)
和韓文 (euc-kr) 之間的識(shí)別。
而對(duì)于普通用戶而言,
肉眼看出一個(gè)文件的編碼方式也是很不現(xiàn)實(shí)的事情。
因此,
滇狐強(qiáng)烈推薦水木社區(qū)的 mbbill 開發(fā)的 fencview 插件。
該插件使用詞頻統(tǒng)計(jì)的方式識(shí)別編碼,
正確率非常高。