-
Notifications
You must be signed in to change notification settings - Fork 0
/
understand-vim-encoding.html
301 lines (290 loc) · 21.2 KB
/
understand-vim-encoding.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
<!DOCTYPE html>
<html lang="en-US">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="author" content="littlewhite" />
<meta name="copyright" content="littlewhite" />
<meta property="og:type" content="article" />
<meta name="twitter:card" content="summary">
<meta name="keywords" content="vim, Tool, " />
<meta property="og:title" content="深入理解vim编码设置 "/>
<meta property="og:url" content="https://chukeer.github.io/understand-vim-encoding.html" />
<meta property="og:description" content="vim的使用环境比较复杂,可以通过terminal在本地使用(比如Mac或Linux主机),也可以ssh连接到远程服务器使用,还可以使用gvim。这里主要讨论terminal下的使用,搞清楚了vim在terminal下的编码设置,gvim相对更简单,自然也就了解了 首先我们要理解字符和字节的区别,字符是用来显示的,而字节是存储和传输时使用,网络传输的是字节流,文件存储的也是字节流,而编辑器要显示文件内容,就需要转化为字符来显示,字符和字节之间的关系可以定义如下 encode(字符, 编码方案) -> 字节 decode(字节, 编码方案) -> 字符 可见encode和decode是一对逆向操作,它们都需要指定编码方案,如果编码方案不一致,则会操作失败 通过terminal操作远程vim时,其数据流向可以表示如下 terminal -> 本地shell -> ssh -> 远程shell -> vim 在这个流向里,只有terminal和vim需要显示字符,其它进程或服务只是做数据传输,如果只是单纯传递二进制数据,是不需要涉及编码解码的,只有当显示字符的时候才需要进行解码,因此只有terminal和vim需要配置编码,而terminal需要和本地shell打交道,远程vim也需要和shell打交道,shell的编码也至关重要 Terminal编码¶ terminal本身也是一个进程,最终的字符显示都需要由terminal来完成,我们在terminal上输入字符也会由它进行编码之后再传递 ..." />
<meta property="og:site_name" content="楚客" />
<meta property="og:article:author" content="littlewhite" />
<meta property="og:article:published_time" content="2017-02-22T00:00:00+08:00" />
<meta property="" content="2017-02-22T00:00:00+08:00" />
<meta name="twitter:title" content="深入理解vim编码设置 ">
<meta name="twitter:description" content="vim的使用环境比较复杂,可以通过terminal在本地使用(比如Mac或Linux主机),也可以ssh连接到远程服务器使用,还可以使用gvim。这里主要讨论terminal下的使用,搞清楚了vim在terminal下的编码设置,gvim相对更简单,自然也就了解了 首先我们要理解字符和字节的区别,字符是用来显示的,而字节是存储和传输时使用,网络传输的是字节流,文件存储的也是字节流,而编辑器要显示文件内容,就需要转化为字符来显示,字符和字节之间的关系可以定义如下 encode(字符, 编码方案) -> 字节 decode(字节, 编码方案) -> 字符 可见encode和decode是一对逆向操作,它们都需要指定编码方案,如果编码方案不一致,则会操作失败 通过terminal操作远程vim时,其数据流向可以表示如下 terminal -> 本地shell -> ssh -> 远程shell -> vim 在这个流向里,只有terminal和vim需要显示字符,其它进程或服务只是做数据传输,如果只是单纯传递二进制数据,是不需要涉及编码解码的,只有当显示字符的时候才需要进行解码,因此只有terminal和vim需要配置编码,而terminal需要和本地shell打交道,远程vim也需要和shell打交道,shell的编码也至关重要 Terminal编码¶ terminal本身也是一个进程,最终的字符显示都需要由terminal来完成,我们在terminal上输入字符也会由它进行编码之后再传递 ...">
<title>深入理解vim编码设置 · 楚客
</title>
<!--
<link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet">
<link href="//netdna.bootstrapcdn.com/font-awesome/4.0.1/css/font-awesome.css" rel="stylesheet">
--!>
<link href="https://chukeer.github.io/theme/css/bootstrap-combined.min.css" rel="stylesheet">
<link href="https://chukeer.github.io/theme/css/font-awesome.css" rel="stylesheet">
<link rel="stylesheet" type="text/css" href="https://chukeer.github.io/theme/css/pygments.css" media="screen">
<link rel="stylesheet" type="text/css" href="https://chukeer.github.io/theme/tipuesearch/tipuesearch.css" media="screen">
<link rel="stylesheet" type="text/css" href="https://chukeer.github.io/theme/css/elegant.css" media="screen">
<link rel="stylesheet" type="text/css" href="https://chukeer.github.io/theme/css/custom.css" media="screen">
</head>
<body>
<div id="content-sans-footer">
<div class="navbar navbar-static-top">
<div class="navbar-inner">
<div class="container-fluid">
<a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</a>
<a class="brand" href="https://chukeer.github.io/"><span class=site-name>楚客</span></a>
<div class="nav-collapse collapse">
<ul class="nav pull-right top-menu">
<li ><a href="https://chukeer.github.io">Home</a></li>
<li ><a href="https://chukeer.github.io/categories.html">Categories</a></li>
<li ><a href="https://chukeer.github.io/tags.html">Tags</a></li>
<li ><a href="https://chukeer.github.io/archives.html">Archives</a></li>
<li><form class="navbar-search" action="https://chukeer.github.io/search.html" onsubmit="return validateForm(this.elements['q'].value);"> <input type="text" class="search-query" placeholder="Search" name="q" id="tipue_search_input"></form></li>
</ul>
</div>
</div>
</div>
</div>
<div class="container-fluid">
<div class="row-fluid">
<div class="span1"></div>
<div class="span10">
<article>
<div class="row-fluid">
<header class="page-header span10 offset2">
<h1><a href="https://chukeer.github.io/understand-vim-encoding.html"> 深入理解vim编码设置 </a></h1>
</header>
</div>
<div class="row-fluid">
<div class="span2 table-of-content">
<nav>
<h4>Contents</h4>
<div class="toc">
<ul>
<li><a href="#terminal">Terminal编码</a></li>
<li><a href="#shell">shell编码</a></li>
<li><a href="#vim">Vim编码</a><ul>
<li><a href="#_1">打开文件</a></li>
<li><a href="#_2">修改文件</a></li>
</ul>
</li>
<li><a href="#vim_1">vim编码配置终极方案</a></li>
</ul>
</div>
</nav>
</div>
<div class="span8 article-content">
<p>vim的使用环境比较复杂,可以通过terminal在本地使用(比如Mac或Linux主机),也可以ssh连接到远程服务器使用,还可以使用gvim。这里主要讨论terminal下的使用,搞清楚了vim在terminal下的编码设置,gvim相对更简单,自然也就了解了</p>
<p>首先我们要理解字符和字节的区别,字符是用来显示的,而字节是存储和传输时使用,网络传输的是字节流,文件存储的也是字节流,而编辑器要显示文件内容,就需要转化为字符来显示,字符和字节之间的关系可以定义如下</p>
<div class="highlight"><pre><span></span>encode(字符, 编码方案) -> 字节
decode(字节, 编码方案) -> 字符
</pre></div>
<p>可见encode和decode是一对逆向操作,它们都需要指定编码方案,如果编码方案不一致,则会操作失败</p>
<p>通过terminal操作远程vim时,其数据流向可以表示如下</p>
<div class="highlight"><pre><span></span>terminal -> 本地shell -> ssh -> 远程shell -> vim
</pre></div>
<p>在这个流向里,只有terminal和vim需要显示字符,其它进程或服务只是做数据传输,如果只是单纯传递二进制数据,是不需要涉及编码解码的,只有当显示字符的时候才需要进行解码,因此只有terminal和vim需要配置编码,而terminal需要和本地shell打交道,远程vim也需要和shell打交道,shell的编码也至关重要</p>
<h2 id="terminal">Terminal编码<a class="headerlink" href="#terminal" title="Permanent link">¶</a></h2>
<p>terminal本身也是一个进程,最终的字符显示都需要由terminal来完成,我们在terminal上输入字符也会由它进行编码之后再传递,简单来说就是</p>
<ol>
<li>输入时,terminal将字符编码为二进制,传递给其它进程或服务</li>
<li>显示时,terminal接收到其它进程或服务的二进制数据流,解码为字符进行显示</li>
</ol>
<p>这里编解码方案就是terminal需要配置的</p>
<h2 id="shell">shell编码<a class="headerlink" href="#shell" title="Permanent link">¶</a></h2>
<p>locale命令也可查看shell编码设置,以LC_开头的代表系统不同类别的编码方案,分为如下几类</p>
<ol>
<li>语言符号及其分类(LC_CTYPE)</li>
<li>数字(LC_NUMERIC)</li>
<li>比较和排序习惯(LC_COLLATE)</li>
<li>时间显示格式(LC_TIME)</li>
<li>货币单位(LC_MONETARY)</li>
<li>信息主要是提示信息,错误信息,状态信息,标题,标签,按钮和菜单等(LC_MESSAGES)</li>
<li>姓名书写方式(LC_NAME)</li>
<li>地址书写方式(LC_ADDRESS)</li>
<li>电话号码书写方式(LC_TELEPHONE)</li>
<li>度量衡表达方式 (LC_MEASUREMENT)</li>
<li>默认纸张尺寸大小(LC_PAPER)</li>
<li>对locale自身包含信息的概述(LC_IDENTIFICATION)。</li>
</ol>
<p>至于最终选什么方案,其优先级如下</p>
<div class="highlight"><pre><span></span>LC_ALL > LC_* > LANG
</pre></div>
<p>也就是说一切都以LC_ALL为主,如果没有设置,则查找LC_*对应的设置项,如果仍旧没有,则使用LANG的设置,影响字符显示的为LC_CTYPE项,为了便于描述,后续提到shell编码时一律指LC_ALL项,设置shell编码方式如下</p>
<div class="highlight"><pre><span></span>export LC_ALL=zh_CN.GBK
export LC_ALL=zh_CN.UTF-8
</pre></div>
<blockquote>
<p>terminal编码和shell编码不一致会出现什么情况?</p>
</blockquote>
<p>假设我们本地terminal编码设置为UTF-8,shell编码设置为GBK,当我们在terminal上输入中文字符时,会显示为乱码或不显示</p>
<p>我们分析一下在终端输入shell命令时的数据交互</p>
<div class="highlight"><pre><span></span>输入法 -> terminal -> shell -> terminal
</pre></div>
<ol>
<li>在terminal上输入字符,terminal根据自己的编码设置,将字符编码为utf8字节,传递给shell</li>
<li>shell收到二进制数据,转码为gbk格式数据,再回传给terminal显示。这一步转码会出错</li>
<li>terminal收到二进制数据,按utf8方式解码为字符并显示。这一步解码会出错</li>
</ol>
<p>将terminal和shell看做两个服务,它们之间需要进行数据交互,在发送数据时进行编码,在收到数据时会进行解码,如果编码方案和解码方案不一致,就会导致乱码或失败,表现形式就是在terminal上输入中文命令时会显示异常,执行结果也不符合预期</p>
<p>如果用ssh登陆远程shell,则远程shell的编码配置和本地shell一致,在通过<code>ssh -v</code>可以打印ssh在登陆过程中做了哪些事</p>
<p>因此我们第一个要点是 </p>
<blockquote>
<p><strong>terminal和shell编码必须设置为一样</strong></p>
</blockquote>
<h2 id="vim">Vim编码<a class="headerlink" href="#vim" title="Permanent link">¶</a></h2>
<p>vim和编码相关的有4个设置项</p>
<ul>
<li><code>fileencodings</code> 一个编码列表,以逗号分隔,打开文件时会依次以列表里的编码方式去解码,如果执行成功,则该编码为文件编码,并设置fileencoding</li>
<li><code>fileencoding</code> 检测到的文件编码</li>
<li><code>encoding</code> vim内部使用的编码,包括文件内容,寄存器等</li>
<li><code>termencoding</code> terminal编码,在terminal中使用vim时会用到,gvim不需要设置</li>
</ul>
<p>可见vim的编码设置相当复杂,我们还是以具体的实例来分析这些编码设置的作用</p>
<p>不管是打开本地vim,还是打开远程vim,我们首先保证本地shell的编码设置和terminal一致,这样涉及到编解码的数据流可以简化为</p>
<div class="highlight"><pre><span></span>terminal -> vim
</pre></div>
<h3 id="_1">打开文件<a class="headerlink" href="#_1" title="Permanent link">¶</a></h3>
<p>vim打开文件,最终还是在terminal上显示,这个过程和编码设置相关的有</p>
<ol>
<li>打开文件,根据fileencodings设置项检测文件编码,并设置fileencoding为对应编码</li>
<li>根据encoding设置项,将文件二进制进行编码转换,存储到内存中</li>
<li>根据termencoding设置项,将内存中的二进制转化为对应编码,传输给terminal</li>
<li>terminal根据自身的编码设置,将收到的数据解码并显示</li>
</ol>
<p>可见vim在打开文件并显示的过程中有大量的编码转化操作,将二进制从编码A转化为编码B的步骤为</p>
<div class="highlight"><pre><span></span>字节流 -> decode(A) -> encode(B) -> 字节流
</pre></div>
<p>最终输出仍旧为字节流,如果A和B不同,则输出字节流和输入就不一样(ascii字节流除外,在所有编码方案里ascii字符对应的字节流都是一样的)。转换成功的前提是,decode所采用的编码方案必须和输入字节流编码方案一致,也就是说如果输入字节流是采用C编码方案生成的,采用A编码方案去解码就会失败</p>
<p>如果vim的某些编码项没有设置,会使用其依赖项的设置或默认设置,依赖关系如下</p>
<div class="highlight"><pre><span></span>termencoding -> encoding -> shell
</pre></div>
<p>vim的这些编码设置项里通常我们只设置fileencodings和encoding,如果只在中英文环境下使用,可设置如下</p>
<div class="highlight"><pre><span></span>set fileencodings=utf8,gbk
set encoding=utf8
</pre></div>
<p>encoding一定要设置utf8,因为utf8可以表示所有字符</p>
<blockquote>
<p>terminal编码和vim的encoding编码不一致会出现什么情况?</p>
</blockquote>
<p>假设terminal编码设置为gbk,vim的encoding为utf8,此时我们打开一个文件,不管这个文件是utf8还是gbk编码,它都无法正常显示</p>
<p>前面提到,vim的termencoding默认会继承encoding的设置,对应前面打开文件的步骤如下</p>
<ol>
<li>打开文件,检测文件编码。这里不管是utf8还是gbk都没有影响</li>
<li>将文件内容转化为utf8格式,存储到内存中。这一步由于知道了文件的原始编码,因此转换不会出错</li>
<li>将内存数据转化为termencoding对应的编码,传输给terminal。由于termencoding继承自encoding设置,因此这一步实际上不需要做编码转换</li>
<li>terminal按gbk解码。问题出在这一步,由于terminal不知道vim传过来的数据是什么编码,它会直接按照自己的编码设置进行解码,编码不一致导致出错</li>
</ol>
<p>如果要正常显示,只需要临时修改vim的termencoding编码和terminal编码一致即可,termencoding只涉及到显示,不涉及文件内容的改变,切勿修改encoding项,准确来说,在任何时候都不要试图修改encoding设置</p>
<p>因此我们的第二个要点是</p>
<blockquote>
<p><strong>vim的termencoding(继承自encoding)必须和terminal编码设置一致</strong></p>
</blockquote>
<h3 id="_2">修改文件<a class="headerlink" href="#_2" title="Permanent link">¶</a></h3>
<p>如果说打开文件的数据流是从vim到terminal,那修改文件则是从terminal到vim再到terminal这么一个来回</p>
<div class="highlight"><pre><span></span>terminal -> vim -> terminal
</pre></div>
<p>和编码相关的步骤如下,打开文件显示的过程前面已经描述过,这里只说修改和保存的过程</p>
<ol>
<li>在terminal输入字符,根据terminal编码方案进行编码,传输给vim</li>
<li>vim收到二进制数据,将数据由termencoding编码转换为encoding编码并保存在内存中</li>
<li>保存文件时,将数据从encoding编码转为fileencoding编码,若fileencoding为空,则直接以encoding方案保存</li>
</ol>
<p>fileencoding有两种情况</p>
<ol>
<li>打开空文件,fileencoding默认为空</li>
<li>打开已经存在的文件,fileencoding是根据fileencodings中的编码列表匹配到的编码方案,若都没匹配上,则为空</li>
</ol>
<p>由上可见,encoding方案编码的数据在vim中是一个中转站,接收数据时(从文件读取或从终端输入)都要转化为encoding编码方案,保存文件时再由encoding编码方案转化为fileencoding编码方案。因此encoding必须设定为一个能表示所有字符的编码方案,通常我们设置为utf8</p>
<blockquote>
<p>vim的encoding编码设置和terminal编码设置不同,如何正常输入文字</p>
</blockquote>
<p>假设terminal和shell的编码设置均为gbk,vim的encoding设置为utf8,如果想正常输入和显示字符,必须将termencoding设置和terminal编码一致,这是不管是显示字符还是输入字符保存文件,都可以正常工作</p>
<p>我们可以设置编码不一致只是为了演示编码的影响,在实际环境中,必须保证这些编码设置都一致,因此终极要点是</p>
<blockquote>
<p><strong>terminal编码,shell编码,以及vim的encoding均设置为utf8</strong></p>
</blockquote>
<h2 id="vim_1">vim编码配置终极方案<a class="headerlink" href="#vim_1" title="Permanent link">¶</a></h2>
<ol>
<li>terminal编码设置为utf8</li>
<li>shell编码设置为utf8, <code>export LC_ALL=zh_CN.UTF-8</code></li>
<li>vim设置encoding为utf8,<code>set encoding=utf-8</code></li>
<li>vim设置fileencodings,<code>set fileencodings=utf-8, gbk</code></li>
</ol>
<hr/>
<aside>
<nav>
<ul class="articles-timeline">
<li class="previous-article">« <a href="https://chukeer.github.io/C++数据库操作之SOCI.html" title="Previous: C++数据库操作之SOCI">C++数据库操作之SOCI</a></li>
<li class="next-article"><a href="https://chukeer.github.io/cppcheck使用方式详解.html" title="Next: cppcheck使用方式详解">cppcheck使用方式详解</a> »</li>
</ul>
</nav>
</aside>
</div>
<section>
<div class="span2" style="float:right;font-size:0.9em;">
<table class="table">
<!-- <time pubdate="pubdate" datetime="2017-02-22T00:00:00+08:00"> 2 22, 2017</time> -->
<tr>
<td>Published</td>
<td><time pubdate="pubdate" datetime="2017-02-22T00:00:00+08:00">2017- 2-22</time></td>
</tr>
<tr>
<td>Category</td>
<td><a class="category-link" href="https://chukeer.github.io/categories.html#tool-ref">Tool</a></td>
</tr>
<tr>
<td>Tags</td>
<td>
<ul class="list-of-tags tags-in-article">
<li><a href="https://chukeer.github.io/tags.html#vim-ref">vim
<span>4</span>
</a></li>
</ul>
</td>
</tr>
</table>
</div>
</section>
</div>
</article>
</div>
<div class="span1"></div>
</div>
</div>
<div id="push"></div>
</div>
<footer>
<div id="footer">
<ul class="footer-content">
<li class="elegant-power">Powered by <a href="http://getpelican.com/" title="Pelican Home Page">Pelican</a>. Theme: <a href="http://oncrashreboot.com/pelican-elegant" title="Theme Elegant Home Page">Elegant</a> by <a href="http://oncrashreboot.com" title="Talha Mansoor Home Page">Talha Mansoor</a></li>
</ul>
</div>
</footer> <!--
<script src="http://code.jquery.com/jquery.min.js"></script>
<script src="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js"></script>
-->
<script src="https://chukeer.github.io/theme/js/jquery.min.js"></script>
<script src="https://chukeer.github.io/theme/js/bootstrap.min.js"></script>
<script>
function validateForm(query)
{
return (query.length > 0);
}
</script>
<script>
$("div.article-content table").addClass("table table-hover");
</script>
</body>
<!-- Theme: Elegant built for Pelican
License : http://oncrashreboot.com/pelican-elegant -->
</html>