Vim命令_Linux Vim命令:替換文字內容

2020-07-16 10:04:30
在講技術之前,有必要給大家介紹一下 Vi 和 Vim 的發展史,從而更全面地了解 Vi 和 Vim。

Vi 的歷史非常悠久,可以追溯到 1976年,那時,一個叫作 Bill Joy 的美國兄弟編寫了一款行編輯器工具,叫 ex,在當時非常的出名。但是,經過對使用者行為的觀察,Joy 發現人們更願意使用 ex 的視覺化模式,而非行編輯模式。因此,Joy 決定在 1979 年發布 Vi 這款編輯器,直接把視覺化模式(Visual Mode)呈現給使用者。正是這個決定造就了今天家喻戶曉的 Vi 編輯器。而 Joy 後來成為了 Sun 公司的創始人之一,並擔任公司首席科學家直到 2003 年。

雖然 Vi 歷史悠久,但是要說群眾基礎,還是 Vim 更勝一籌。Vim 是由一位荷蘭牛人開發的視覺化文字編輯器。起初,他對 Vim 的定位並不高,從他給這款產品命名 Vi IMitation 就能看得出來。而後來由於加入的特性越來越多,也越來越受到人們的喜愛和歡迎,因此他也順勢將 Vim 的名字全稱改為了 Vi IMproved,意為 Vi 的增強版本,看來英文也是博大精深啊。

這位開發了 Vim 的荷蘭人,叫作布萊姆·米勒(Bram Moolenaar),他不僅一直在不計酬勞地為開源事業做著貢獻,而且還持續資助烏干達改善兒童教育和醫療水平。同時,他還是一個相當有趣的人,在他的個人主頁上,他用數十種語言寫出了他的名字“米勒”。

說到 Vim 與 Vi 的關係,可以確定的是 Vi 的所有功能幾乎都已經囊括到了 Vim 中,同時 Vim 較 Vi 的優勢和亮點也是不勝列舉的,比如:
  • Vim 支援更多語言的語法高亮。
  • Vim 支援更多的作業系統和平台,包括 UNIX/Linux、Windows、MAC 等。
  • Vim 支援強大的外掛功能。
  • Vim 支援通過 SSH/HTTP 方式的遠端文字編輯功能。
  • Vim 支援多層級的 undo 和 redo。
  • Vim 可以直接編輯壓縮包(gzip、bzip2、zip)中的檔案。

如果套用一句蘋果的廣告語,那就是:“唯一的不同,是處處都不同!”

由於 Vim 使用的廣泛性,本文下面內容中出現的 Vi 都是指代 Vim。

基礎替換用法

在 Vi 的普通模式下,先輸入冒號(:),進入命令列模式,這是 Vi 做一切替換操作的前提。

假如我們想將 abc 替換為 xyz,那麼就這樣:
:s/abc/xyz/

不過要特別注意,這個替換沒有你想象得那麼順利,因為它只能針對游標當前所在行進行替換,而且更糟糕的是,它只替換當前行中第一個匹配到的 abc。

舉個例子,如果此行內容為“I write abc,I read xyz and abc.”。那麼替換後的結果為“I write xyz,I read xyz and abc.”。

接下來,我們的改進方案來了,請注意,我們在替換命令的最後面加上了 g 這個字母:
:s/abc/xyz/g

這樣可以實現在游標所在行,對所有匹配到的 abc 都替換為 xyz。繼續舉這個例子,如果此行內容為“I write abc,I read xyz and abc.”。那麼替換後的結果為“I write xyz,I read xyz and xyz.”。

可惜的是,這個方案仍局限在游標所在行,還是無法替換檔案中所有行中的 abc。所以,我們的方案繼續改進,我們在替換命令的最前面加上了“1,$”的表示式:
:1,$s/abc/xyz/g

其實我們可以在替換命令的最前面加上類似“m,n”格式的表示式,來表示替換動作所能影響到的行範圍,1 表示第一行,$ 表示最後一行。當然你也完全可以指定其他行範圍,比如,10,50s/abc/xyz/g 就表示只替換第 10 行到第 50 行中的 abc。

在這裡再教你一個小技巧,如果你想做全文替換,寫 1,$ 要三個字元,而用 % 來代替,只需要一個字元,所以我們的替換命令可以改寫為:
:%s/abc/xyz/g

跳脫替換

如果想將當前行裡所有的“S.”替換為“S->”,就需要用到跳脫符了,正確的寫法是這樣的:
:s/S./S->/g

我們假設當前行的內容是:
S.abc and S->bcd and S.aaa and S..abc

替換後會變為:
S->abc and S->bcd and S->aaa and S->.abc

此處因為點號“.”為特殊匹配符,在正則中表示單個字元,所以如果想匹配點號,就需要把“”放在點號前面,表示取消點號的特殊意義。

連間隔符都可以改變

如果你要匹配和替換“http://roclinux.cn/index.php”這樣一個 URL,你會發現這很麻煩,正確的寫法會嚇到你,來看一看:
:%s/http://roclinux.cn/index.php/https://www.baidu.com/index.php/g

看都看暈了,裡面好多的正斜線“”和反斜線“/”啊,真是一個反人類的替換表示式。

為了保護人類,Vim 允許我們自定義間隔符,比如我們可以用 # 來替換/,如 s/abc/xyz/ 可以替換為 s#abc#xyz#,或者 s!abc!xyz!都是可以的。

我們再次來改良一下上面那個反人類的替換表示式吧:
:%s#http://roclinux.cn/index.php#https://www.baidu.com/index.php#g

最複雜的壓軸

如果我希望在含有日期格式(XXXX-XX-XX)的字串兩側加上一對單引號,即 2008-07-01 變成‘2008-07-01’,應該如何寫這個替換表示式呢?

之所以舉這個例子,是因為我們可以通過這個例子學到好幾個重要的技巧,大家清醒一下頭腦,我們一起攻克這最後一個難題。

例如,原來檔案內容為:
aaa 2008-07-01 bbb
ccc 2008-07-12 aaa

我們需要用下面的替換命令來實現加引號的效果:
:1,$s/([0-9]{4}-[0-9]{2}-[0-9]{2})/'1'/g

替換後為:
aaa '2008-07-01' bbb
ccc '2008-07-12' aaa

這個替換命令比較複雜,我們要逐步解釋一下,這裡面共涉及了三個知識點:

第一個知識點:[0-9] 表示 0 到 9 之間的任一個數位,這是正則中表示數位集合的標準寫法。

第二個知識點:{n} 表示將此符號前面的元素重複 n 遍,所以 [0-9]{4} 就表示一個四位數的數位。

第三個知識點:如果在匹配方案中用到了(),則表示要暫存括號中所匹配到的內容,而 1 表示替換為暫存的內容(題外話:如果存在多個括號組,則後面要通過編號來依次對應,如 1、2、3 等)。在本例中,我們匹配的是 2008-07-01,那麼加了括號後就會被暫存起來,而在後面的 1 處就會被替換過來,外面再加一對引號,就完成了!

Vim 的替換,包含的知識點和技巧遠不止本文所提及的內容,還有非常多的知識等待著大家去學習和積累。