Vim命令_Linux Vim命令:替换文本内容
在讲技术之前,有必要给大家介绍一下 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 bbbccc 2008-07-12 aaa
我们需要用下面的替换命令来实现加引号的效果:
:1,$s/\([0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}\)/'\1'/g
替换后为:
aaa '2008-07-01' bbbccc '2008-07-12' aaa
这个替换命令比较复杂,我们要逐步解释一下,这里面共涉及了三个知识点:
第一个知识点:[0-9] 表示 0 到 9 之间的任一个数字,这是正则中表示数字集合的标准写法。
第二个知识点:{n} 表示将此符号前面的元素重复 n 遍,所以 [0-9]{4} 就表示一个四位数的数字。
第三个知识点:如果在匹配方案中用到了(),则表示要暂存括号中所匹配到的内容,而 \1 表示替换为暂存的内容(题外话:如果存在多个括号组,则后面要通过编号来依次对应,如 \1、\2、\3 等)。在本例中,我们匹配的是 2008-07-01,那么加了括号后就会被暂存起来,而在后面的 \1 处就会被替换过来,外面再加一对引号,就完成了!
Vim 的替换,包含的知识点和技巧远不止本文所提及的内容,还有非常多的知识等待着大家去学习和积累。