首先我们要理解字符和字节的区别,字符是用来显示的,而字节是存储和传输时使用,网络传输的是字节流,文件存储的也是字节流,而编辑器要显示文件内容,就需要转化为字符来显示,字符和字节之间的关系可以定义如下
可见encode和decode是一对逆向 *** 作,它们都需要指定编码方案,如果编码方案不一致,则会 *** 作失败
通过terminal *** 作远程vim时,其数据流向可以表示如下
在这个流向里,只有terminal和vim需要显示字符,其它进程或服务只是做数据传输,如果只是单纯传递二进制数据,是不需要涉及编码解码的,只有当显示字符的时候才需要进行解码,因此只有terminal和vim需要配置编码,而terminal需要和本地shell打交道,远程vim也需要和shell打交道,shell的编码也至关重要
terminal本身也是一个进程,最终的字符显示都需要由terminal来完成,我们在terminal上输入字符也会由它进行编码之后再传递,简单来说就是
这里编解码方案就是terminal需要配置的
locale命令也可查看shell编码设置,以LC_开头的代表系统不同类别的编码方案,分为如下几类
至于最终选什么方案,其优先级如下
也就是说一切都以LC_ALL为主,如果没有设置,则查找LC_*对应的设置项,如果仍旧没有,则使用LANG的设置,影响字符显示的为LC_CTYPE项,为了便于描述,后续提到shell编码时一律指LC_ALL项,设置shell编码方式如下
假设我们本地terminal编码设置为UTF-8,shell编码设置为GBK,当我们在terminal上输入中文字符时,会显示为乱码或不显示
我们分析一下在终端输入shell命令时的数据交互
将terminal和shell看做两个服务,它们之间需要进行数据交互,在发送数据时进行编码,在收到数据时会进行解码,如果编码方案和解码方案不一致,就会导致乱码或失败,表现形式就是在terminal上输入中文命令时会显示异常,执行结果也不符合预期
如果用ssh登陆远程shell,则远程shell的编码配置和本地shell一致,在通过 ssh -v 可以打印ssh在登陆过程中做了哪些事
因此我们第一个要点是
vim和编码相关的有4个设置项
可见vim的编码设置相当复杂,我们还是以具体的实例来分析这些编码设置的作用
不管是打开本地vim,还是打开远程vim,我们首先保证本地shell的编码设置和terminal一致,这样涉及到编解码的数据流可以简化为
vim打开文件,最终还是在terminal上显示,这个过程和编码设置相关的有
可见vim在打开文件并显示的过程中有大量的编码转化 *** 作,将二进制从编码A转化为编码B的步骤为
最终输出仍旧为字节流,如果A和B不同,则输出字节流和输入就不一样(ascii字节流除外,在所有编码方案里ascii字符对应的字节流都是一样的)。转换成功的前提是,decode所采用的编码方案必须和输入字节流编码方案一致,也就是说如果输入字节流是采用C编码方案生成的,采用A编码方案去解码就会失败
如果vim的某些编码项没有设置,会使用其依赖项的设置或默认设置,依赖关系如下
vim的这些编码设置项里通常我们只设置fileencodings和encoding,如果只在中英文环境下使用,可设置如下
encoding一定要设置utf8,因为utf8可以表示所有字符
假设terminal编码设置为gbk,vim的encoding为utf8,此时我们打开一个文件,不管这个文件是utf8还是gbk编码,它都无法正常显示
前面提到,vim的termencoding默认会继承encoding的设置,对应前面打开文件的步骤如下
如果要正常显示,只需要临时修改vim的termencoding编码和terminal编码一致即可,termencoding只涉及到显示,不涉及文件内容的改变,切勿修改encoding项,准确来说,在任何时候都不要试图修改encoding设置
因此我们的第二个要点是
如果说打开文件的数据流是从vim到terminal,那修改文件则是从terminal到vim再到terminal这么一个来回
和编码相关的步骤如下,打开文件显示的过程前面已经描述过,这里只说修改和保存的过程
fileencoding有两种情况
由上可见,encoding方案编码的数据在vim中是一个中转站,接收数据时(从文件读取或从终端输入)都要转化为encoding编码方案,保存文件时再由encoding编码方案转化为fileencoding编码方案。因此encoding必须设定为一个能表示所有字符的编码方案,通常我们设置为utf8
假设terminal和shell的编码设置均为gbk,vim的encoding设置为utf8,如果想正常输入和显示字符,必须将termencoding设置和terminal编码一致,这是不管是显示字符还是输入字符保存文件,都可以正常工作
我们可以设置编码不一致只是为了演示编码的影响,在实际环境中,必须保证这些编码设置都一致,因此终极要点是
vim ~/.vimrc
配置如下内容
vim 会依次尝试 fileencodings 指定的编码
:set fileencoding
vim xxx.txt -c "e ++enc=gbk"
在Vim中直接进行转换文件编码,比如将一个文件转换成utf-8格式
:set fileencoding=utf-8
查看文件格式
:set fileformat?
设置文件格式为 unix
:set fileformat=unix
Vim无疑是世间最强的编辑器(之一)了,但是强大的代价有时候就是必须要花上更多的功夫来应付。中文的编码问题无疑是中文用户值得一提的一个典型问题了,作为老用户的我为此曾经狠狠的中q过三次,到了最近这一次,我决定要好好的写下来,为了记忆日渐衰退的自己留下一点方便查找的记录了。
大概七八年前吧,那时候还对Vim不算熟悉,刚从UE转投而来的我,当头就吃了一记闷棍,花了好大的功夫才理解了原来还有用户自己捣鼓好文件编码这回事情,到处查找之后,算是得到了如下的一点知识:
set fileencodings=ucs-bom,utf-8,cp936,gb18030,big5,euc-jp,euc-kr,latin1
set fileencoding=utf-8
set encoding=utf-8
这些配置在网上随便一查,就不难理解:
encoding用来指导Vim理解自己内部处理和显示的缺省编码;
fileencodings则是决定Vim识别文件编码格式的识别序列,应当按照从严格到宽松的角度来摆放;
fileencoding设置文件保存时的编码格式;
于是,在这样一个配置的加持下,我无风无雨的渡过了好几年的Vim使用——正当我志得意满,自以为对Vim已经比较了解的情况下,两年前有次在Linux下Term中使用Vim过程中却遇到了久违的乱码,当我试了好几次都无法解决之后,才终于开始满世界的寻求解决(过程中,甚至萌生过转投其他编辑器的想法),在数次绝望之后终于找到了原因,依赖于「termencoding」这个参数指导的term侧的显示终于的得到了解决,至此我以为万事大吉,甚至把Vimrc都留档备份,准备以后千秋万代了:
set termencoding=gbk
好吧,高潮在后头,就在最近刚刚装了个新机器,英文版的Windows7,Vim7.4——然后,赫然发现方块乱码又出现了!我各种挣扎和搜索,都没有找到原因,再次绝望之际,一篇小小的文章却告诉我,原来我一直以为还是编解码识别导致的问题,实际上却是货真价实的显示问题罢了——英文Windows下的Vim不知道如何显示双倍字符宽度的字体!你必须告诉它:
set gfn=Monaco:h10:cANSI
set gfw=NSimsun:h12
如上,设置了英文字体使用Monaco,中文字体用NSimsun,至此,才彻底搞定了这个问题。
果真,我生有涯而学无涯啊,希望以后不要再折腾这个了……
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)