Vim 编码问题详解
vim 中有 4 个与编码相关的配置,分别是
encoding
、termencoding
、fileencoding
和fileencodings
。在实际使用中任何一个配置有问题都可能会导致乱码,因此我们应该清楚每个配置的含义。
1. encoding
encoding
是 vim 内部使用的字符编码格式。vim 内部所有的 buffer、寄存器、脚本中的字符串等,都使用的是该配置的编码格式。如果文件的编码格式与内部编码格式不一致,则会先转为内部的编码格式,如果无法转换,则无法转换的字符会丢失。因此在设置内部编码时应该选择一种表现力足够的编码,即编码范围大的格式,比如 UTF-8。
由于 encoding
配置涉及 vim 中所有的字符的内部编码方式,因此,只能在 vim 启动的时候进行设置。如果没有特殊需求,请始终将 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 会把内部编码(encoding)转换为屏幕编码格式,然后再输出到屏幕。如果内部编码中含有无法转换为屏幕编码的字符,那么该字符就会变成问号,但是不会影响编辑操作。
比如,当在 Windows 中使用模拟终端远程连接服务器时,由于 Windows 中的模拟终端编码设置为 GBK 格式,而 Linux 中使用 UTF-8 编码,那么终端中的字符就会乱码,此时有两种方式可以解决此类乱码问题:
- 把 vim 的
encoding
改为 GBK,此时其内部的编码格式(buffer 中的编码格式)与终端的格式就一致了。 - 更改
termencoding
编码格式为 GBK,让 vim 将 buffer 中的字符在显示的时候转换为 GBK 编码,这样终端就可以正常显示了。
对于第一种解决方式,如果遇到编辑的文件中含有 GBK 无法表示的字符时,这些字符就会丢失。使用第二种方式的时候,虽然无法正常显示,但是仍然可以正常编辑(不会影响 buffer 中的内容)。故推荐使用第二种方式。
对于图形界面的下的 Gvim,它的显示不依赖于终端,因此 termencoding
配置无意义。在 GTK2 下的 Gvim 中,termencoding
始终是 utf-8,不能修改。Windows 下的 Gvim 则忽略 termencoding
的配置。
3. fileencoding
当 Vim 从磁盘中读取文件时,会对文件编码格式进行检测,如果文件的编码方式和内部编码方式(encoding
)不同,就会将其转换为内部编码格式。转换完毕后,Vim 会将 fileencoding
设置为文件的编码(检测过程中识别出的编码)。
当 vim 对文件进行保存时,如果 encoding
(内部使用的编码) 和 fileencoding
(文件编码) 不一致,就会进行编码转换,将 buffer 中的数据由 encoding
格式转换成 fileencoding
格式(即原本的文件格式)。
因此,我们可以通过打开文件后重新设置 fileencoding
来进行文件格式的转换,但是这有一个前提:就是 vim 可以正确识别出文件的编码格式,如果格式识别错误是无法通过更改 fileencoding
来进行转换的。
4. fileencodings
上面提到的文件编码检测是通过设置 fileencodings
实现的(注意是复数)。fileencodings
是一个逗号分割的列表,列表中的元素为编码格式名称。
当我们使用 vim 打开文件时,vim 会按顺序使用 fileencodings
中指定的编码尝试解码,如果成功,则使用该编码格式进行转码(由文件编码格式转换为内部编码格式 encoding
),并设置 fileencoding
为该编码格式,如果失败就使用下一种方式尝试解码。
因此,我们在设置 fileencodings
的时候,一定要将编码严格的、解码不正确更容易失败的格式放在列表的前面,将宽松的,包容性好的格式放在后面。
例如,Latin1 是一种非常宽松的编码方式,任何一种编码方式的文本都可以使用它进行解码,不会解码失败,但是,会出现乱码(注意:解码失败 != 乱码)。因此,如果把 latin1 放到了列表的第一个,那么打开文件自动识别的 fileencoding
都是 latin1,都有可能出现乱码的情况。
以下推荐配置:
set fileencodings=ucs-bom,utf-8,cp936,gb18030,big5,euc-jp,euc-kr,latin1
如果 vim 自动检测的编码格式不正确,但是我们知道正确的编码格式,可以使用 ++enc=encoding_type 来打开文件::e ++enc=utf-8 filename
。
下面是对该配置的说明:
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,往往在前面的编码中就被误判了。不过,正如前面所说的,中国用户没有太多机会接触这样的文件。