深入理解vim編碼設(shè)置

vim的使用環(huán)境比較復(fù)雜,可以通過terminal在本地使用(比如Mac或Linux主機),也可以ssh連接到遠(yuǎn)程服務(wù)器使用,還可以使用gvim。這里主要討論terminal下的使用,搞清楚了vim在terminal下的編碼設(shè)置,gvim相對更簡單,自然也就了解了

首先我們要理解字符和字節(jié)的區(qū)別,字符是用來顯示的,而字節(jié)是存儲和傳輸時使用,網(wǎng)絡(luò)傳輸?shù)氖亲止?jié)流,文件存儲的也是字節(jié)流,而編輯器要顯示文件內(nèi)容,就需要轉(zhuǎn)化為字符來顯示,字符和字節(jié)之間的關(guān)系可以定義如下

encode(字符, 編碼方案) -> 字節(jié)
decode(字節(jié), 編碼方案) -> 字符

可見encode和decode是一對逆向操作,它們都需要指定編碼方案,如果編碼方案不一致,則會操作失敗

通過terminal操作遠(yuǎn)程vim時,其數(shù)據(jù)流向可以表示如下

terminal -> 本地shell -> ssh -> 遠(yuǎn)程shell -> vim

在這個流向里,只有terminal和vim需要顯示字符,其它進(jìn)程或服務(wù)只是做數(shù)據(jù)傳輸,如果只是單純傳遞二進(jìn)制數(shù)據(jù),是不需要涉及編碼解碼的,只有當(dāng)顯示字符的時候才需要進(jìn)行解碼,因此只有terminal和vim需要配置編碼,而terminal需要和本地shell打交道,遠(yuǎn)程vim也需要和shell打交道,shell的編碼也至關(guān)重要

Terminal編碼

terminal本身也是一個進(jìn)程,最終的字符顯示都需要由terminal來完成,我們在terminal上輸入字符也會由它進(jìn)行編碼之后再傳遞,簡單來說就是

  1. 輸入時,terminal將字符編碼為二進(jìn)制,傳遞給其它進(jìn)程或服務(wù)
  2. 顯示時,terminal接收到其它進(jìn)程或服務(wù)的二進(jìn)制數(shù)據(jù)流,解碼為字符進(jìn)行顯示

這里編解碼方案就是terminal需要配置的

shell編碼

locale命令也可查看shell編碼設(shè)置,以LC_開頭的代表系統(tǒng)不同類別的編碼方案,分為如下幾類

  1. 語言符號及其分類(LC_CTYPE)
  2. 數(shù)字(LC_NUMERIC)
  3. 比較和排序習(xí)慣(LC_COLLATE)
  4. 時間顯示格式(LC_TIME)
  5. 貨幣單位(LC_MONETARY)
  6. 信息主要是提示信息,錯誤信息,狀態(tài)信息,標(biāo)題,標(biāo)簽,按鈕和菜單等(LC_MESSAGES)
  7. 姓名書寫方式(LC_NAME)
  8. 地址書寫方式(LC_ADDRESS)
  9. 電話號碼書寫方式(LC_TELEPHONE)
  10. 度量衡表達(dá)方式 (LC_MEASUREMENT)
  11. 默認(rèn)紙張尺寸大小(LC_PAPER)
  12. 對locale自身包含信息的概述(LC_IDENTIFICATION)。

至于最終選什么方案,其優(yōu)先級如下

LC_ALL > LC_* > LANG

也就是說一切都以LC_ALL為主,如果沒有設(shè)置,則查找LC_*對應(yīng)的設(shè)置項,如果仍舊沒有,則使用LANG的設(shè)置,影響字符顯示的為LC_CTYPE項,為了便于描述,后續(xù)提到shell編碼時一律指LC_ALL項,設(shè)置shell編碼方式如下

export LC_ALL=zh_CN.GBK
export LC_ALL=zh_CN.UTF-8

terminal編碼和shell編碼不一致會出現(xiàn)什么情況?

假設(shè)我們本地terminal編碼設(shè)置為UTF-8,shell編碼設(shè)置為GBK,當(dāng)我們在terminal上輸入中文字符時,會顯示為亂碼或不顯示

我們分析一下在終端輸入shell命令時的數(shù)據(jù)交互

輸入法 -> terminal -> shell -> terminal
  1. 在terminal上輸入字符,terminal根據(jù)自己的編碼設(shè)置,將字符編碼為utf8字節(jié),傳遞給shell
  2. shell收到二進(jìn)制數(shù)據(jù),轉(zhuǎn)碼為gbk格式數(shù)據(jù),再回傳給terminal顯示。這一步轉(zhuǎn)碼會出錯
  3. terminal收到二進(jìn)制數(shù)據(jù),按utf8方式解碼為字符并顯示。這一步解碼會出錯

將terminal和shell看做兩個服務(wù),它們之間需要進(jìn)行數(shù)據(jù)交互,在發(fā)送數(shù)據(jù)時進(jìn)行編碼,在收到數(shù)據(jù)時會進(jìn)行解碼,如果編碼方案和解碼方案不一致,就會導(dǎo)致亂碼或失敗,表現(xiàn)形式就是在terminal上輸入中文命令時會顯示異常,執(zhí)行結(jié)果也不符合預(yù)期

如果用ssh登陸遠(yuǎn)程shell,則遠(yuǎn)程shell的編碼配置和本地shell一致,在通過ssh -v可以打印ssh在登陸過程中做了哪些事

因此我們第一個要點是

terminal和shell編碼必須設(shè)置為一樣

Vim編碼

vim和編碼相關(guān)的有4個設(shè)置項

  • fileencodings 一個編碼列表,以逗號分隔,打開文件時會依次以列表里的編碼方式去解碼,如果執(zhí)行成功,則該編碼為文件編碼,并設(shè)置fileencoding
  • fileencoding 檢測到的文件編碼
  • encoding vim內(nèi)部使用的編碼,包括文件內(nèi)容,寄存器等
  • termencoding terminal編碼,在terminal中使用vim時會用到,gvim不需要設(shè)置

可見vim的編碼設(shè)置相當(dāng)復(fù)雜,我們還是以具體的實例來分析這些編碼設(shè)置的作用

不管是打開本地vim,還是打開遠(yuǎn)程vim,我們首先保證本地shell的編碼設(shè)置和terminal一致,這樣涉及到編解碼的數(shù)據(jù)流可以簡化為

terminal -> vim

打開文件

vim打開文件,最終還是在terminal上顯示,這個過程和編碼設(shè)置相關(guān)的有

  1. 打開文件,根據(jù)fileencodings設(shè)置項檢測文件編碼,并設(shè)置fileencoding為對應(yīng)編碼
  2. 根據(jù)encoding設(shè)置項,將文件二進(jìn)制進(jìn)行編碼轉(zhuǎn)換,存儲到內(nèi)存中
  3. 根據(jù)termencoding設(shè)置項,將內(nèi)存中的二進(jìn)制轉(zhuǎn)化為對應(yīng)編碼,傳輸給terminal
  4. terminal根據(jù)自身的編碼設(shè)置,將收到的數(shù)據(jù)解碼并顯示

可見vim在打開文件并顯示的過程中有大量的編碼轉(zhuǎn)化操作,將二進(jìn)制從編碼A轉(zhuǎn)化為編碼B的步驟為

字節(jié)流 -> decode(A) -> encode(B) -> 字節(jié)流

最終輸出仍舊為字節(jié)流,如果A和B不同,則輸出字節(jié)流和輸入就不一樣(ascii字節(jié)流除外,在所有編碼方案里ascii字符對應(yīng)的字節(jié)流都是一樣的)。轉(zhuǎn)換成功的前提是,decode所采用的編碼方案必須和輸入字節(jié)流編碼方案一致,也就是說如果輸入字節(jié)流是采用C編碼方案生成的,采用A編碼方案去解碼就會失敗

如果vim的某些編碼項沒有設(shè)置,會使用其依賴項的設(shè)置或默認(rèn)設(shè)置,依賴關(guān)系如下

termencoding -> encoding -> shell

vim的這些編碼設(shè)置項里通常我們只設(shè)置fileencodings和encoding,如果只在中英文環(huán)境下使用,可設(shè)置如下

set fileencodings=utf8,gbk
set encoding=utf8

encoding一定要設(shè)置utf8,因為utf8可以表示所有字符

terminal編碼和vim的encoding編碼不一致會出現(xiàn)什么情況?

假設(shè)terminal編碼設(shè)置為gbk,vim的encoding為utf8,此時我們打開一個文件,不管這個文件是utf8還是gbk編碼,它都無法正常顯示

前面提到,vim的termencoding默認(rèn)會繼承encoding的設(shè)置,對應(yīng)前面打開文件的步驟如下

  1. 打開文件,檢測文件編碼。這里不管是utf8還是gbk都沒有影響
  2. 將文件內(nèi)容轉(zhuǎn)化為utf8格式,存儲到內(nèi)存中。這一步由于知道了文件的原始編碼,因此轉(zhuǎn)換不會出錯
  3. 將內(nèi)存數(shù)據(jù)轉(zhuǎn)化為termencoding對應(yīng)的編碼,傳輸給terminal。由于termencoding繼承自encoding設(shè)置,因此這一步實際上不需要做編碼轉(zhuǎn)換
  4. terminal按gbk解碼。問題出在這一步,由于terminal不知道vim傳過來的數(shù)據(jù)是什么編碼,它會直接按照自己的編碼設(shè)置進(jìn)行解碼,編碼不一致導(dǎo)致出錯

如果要正常顯示,只需要臨時修改vim的termencoding編碼和terminal編碼一致即可,termencoding只涉及到顯示,不涉及文件內(nèi)容的改變,切勿修改encoding項,準(zhǔn)確來說,在任何時候都不要試圖修改encoding設(shè)置

因此我們的第二個要點是

vim的termencoding(繼承自encoding)必須和terminal編碼設(shè)置一致

修改文件

如果說打開文件的數(shù)據(jù)流是從vim到terminal,那修改文件則是從terminal到vim再到terminal這么一個來回

terminal -> vim -> terminal

和編碼相關(guān)的步驟如下,打開文件顯示的過程前面已經(jīng)描述過,這里只說修改和保存的過程

  1. 在terminal輸入字符,根據(jù)terminal編碼方案進(jìn)行編碼,傳輸給vim
  2. vim收到二進(jìn)制數(shù)據(jù),將數(shù)據(jù)由termencoding編碼轉(zhuǎn)換為encoding編碼并保存在內(nèi)存中
  3. 保存文件時,將數(shù)據(jù)從encoding編碼轉(zhuǎn)為fileencoding編碼,若fileencoding為空,則直接以encoding方案保存

fileencoding有兩種情況

  1. 打開空文件,fileencoding默認(rèn)為空
  2. 打開已經(jīng)存在的文件,fileencoding是根據(jù)fileencodings中的編碼列表匹配到的編碼方案,若都沒匹配上,則為空

由上可見,encoding方案編碼的數(shù)據(jù)在vim中是一個中轉(zhuǎn)站,接收數(shù)據(jù)時(從文件讀取或從終端輸入)都要轉(zhuǎn)化為encoding編碼方案,保存文件時再由encoding編碼方案轉(zhuǎn)化為fileencoding編碼方案。因此encoding必須設(shè)定為一個能表示所有字符的編碼方案,通常我們設(shè)置為utf8

vim的encoding編碼設(shè)置和terminal編碼設(shè)置不同,如何正常輸入文字

假設(shè)terminal和shell的編碼設(shè)置均為gbk,vim的encoding設(shè)置為utf8,如果想正常輸入和顯示字符,必須將termencoding設(shè)置和terminal編碼一致,這是不管是顯示字符還是輸入字符保存文件,都可以正常工作

我們可以設(shè)置編碼不一致只是為了演示編碼的影響,在實際環(huán)境中,必須保證這些編碼設(shè)置都一致,因此終極要點是

terminal編碼,shell編碼,以及vim的encoding均設(shè)置為utf8

vim編碼配置終極方案

  1. terminal編碼設(shè)置為utf8
  2. shell編碼設(shè)置為utf8, export LC_ALL=zh_CN.UTF-8
  3. vim設(shè)置encoding為utf8,set encoding=utf-8
  4. vim設(shè)置fileencodings,set fileencodings=utf-8, gbk
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,333評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,491評論 3 416
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 176,263評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,946評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 71,708評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,186評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,255評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,409評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,939評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,774評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,976評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,518評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,209評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,641評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,872評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,650評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 47,958評論 2 373

推薦閱讀更多精彩內(nèi)容

  • 字符集和編碼簡介 在編程中常??梢砸姷礁鞣N字符集和編碼,包括ASCII,MBCS,Unicode等字符集。確切的說...
    蘭山小亭閱讀 8,541評論 0 13
  • 可以看我的博客 lmwen.top 或者訂閱我的公眾號 簡介有稍微接觸python的人就會知道,python中...
    ayuLiao閱讀 3,141評論 1 5
  • 大概每個人在使用軟件時都遇到過亂碼的問題,這是由于字符的編碼和解碼方式不一致導(dǎo)致,我們知道計算機只認(rèn)識二進(jìn)制數(shù)據(jù),...
    楚客閱讀 1,440評論 1 9
  • Ubuntu的發(fā)音 Ubuntu,源于非洲祖魯人和科薩人的語言,發(fā)作 oo-boon-too 的音。了解發(fā)音是有意...
    螢火蟲de夢閱讀 99,426評論 9 467
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,781評論 18 139