我们编写整理代码或文档时,经常需要在字符串两端添加引号、括号、空格等字符,如果不在意效率,可能会浪费许多时间,所以有必要了解一下更高效的方法。

案例一

a = test_string
b = new_string
tmp = strnig with space
result = a + tmp

改成

a = "test_string"
b = "new_string"
tmp = "strnig with space"
result = a + tmp

这是一个比较简单的案例,虽然也涉及意外情况。

我们可以只处理前三行,这样规律就清晰多了,而无需处理第四行的意外。这个规律就是把 = 后的字符串用引号包起来,我们可以直接替换。

:1,3s/= \zs.*/"&"

1,3 是只处理前三行,也可以先用 V3GVjj 选中再处理。= \zs.* 是匹配 = 之后的内容,\zs 是指之前的内容只搜索不匹配。& 指代之前匹配到的内容。这样就可以把三对引号轻松添加上了。

案例二

a = test_string
b = new_string
tmp = strnig with space
result = a + tmp
c = another string
new_result = b + tmp
d = string too

改成

a = "test_string"
b = "new_string"
tmp = "strnig with space"
result = a + tmp
c = "another string"
new_result = b + tmp
d = "string too"

这回又多了三行,上边的规律不能用了,不然得替换三次,麻烦不少。我们需要再找新的规律,好在这个规律也好找,如果出现了加号,就不要替换了。

:%s/= \zs[^+]*$/"&"

其实并没有复杂很多。[^+]*$ 是匹配没有加号的字符串,直到行尾。

案例三

但有时候我们要处理的代码或者数据总是稀奇古怪,充满意外情况,比如把

a = test_string
b = new_string
tmp = strnig with space
result = a + tmp
c = I am + a string
d = another string
new_result = b + tmp
e = string too

改成

a = "test_string"
b = "new_string"
tmp = "strnig with space"
result = a + tmp
c = "I am + a string"
d = "another string"
new_result = b + tmp
e = "string too"

这又打破了刚才的规律,靠加号判断已经不顶用了。在这个例子中,我们还可以继续找规律,改正则表达式,但不是很轻松了。而且总有用一次替换很难解决的场景,所以我们需要换个思路。

像这种规律已经不明显的操作,就没必要继续找规律了,而是各个击破。我们需要一个便捷的操作可以处理一行,然后把它用在不同行中。

:s/= \zs.*/"&"
jVj@:
jjVj@@
G@@

看起来很麻烦,实际操作很自然。第一行和案例一中的命令差不多,只是把作用范围去掉了,因为我们要手动指定范围。之后我们就要选定范围来执行这个命令。jVj 是选定第二行和第三行,@: 是调用刚才用过的命令,即 :...jjVj 是选定第五行和第六行,@@ 是调用上次用过的宏,因为 @: 其实是调用 : 宏。当然也可以和之前一样用 @:,但 @@ 更好按一些。G@@ 同理,处理最后一行。

案例四(待修改)

案例三看起来已经没什么规律了,其实还有一个重要规律,就是每行只需要加一对引号。但有些时候一行需要加多对引号,比如把

a = test_string + new string + good
b = new_string
tmp = strnig with space
result = a + tmp
c = I am + a string + b
d = another string
new_result = b + tmp

改成

a = "test_string" + "new string" + "good"
b = "new_string"
tmp = "strnig with space"
result = a + tmp
c = "I am + a string" + b
d = "another string"
new_result = b + tmp

这就更加混乱了,规律已经很难用语言描述。如果遇到这样的场景,有什么办法可以省点事吗?

和刚才一样,规则变复杂后,想继续用正则表达式替换,就有些吃力不讨好了,可能用了几分钟想出来了,但换别的方法早就处理完了。在规律比较混乱的场景,我们需要以不变应万变,而不是被规律牵着鼻子走。

因为一行可能会添加多对引号,我们就需要把操作的粒度从行降到字符串,然后根据实际情况依次处理。这个字符串还没有什么规律,可能包含空格,也可能包含加号。

/= <CR>
wveqqc""<Esc>PWWq
vee@q
ve@@
wve@@
wv$h@@
nwvfg@@
nwv$h@@

看起来挺复杂的,因为这个场景本身就很复杂,很难简化,如果不使用宏,还要麻烦许多。/= <CR> 是定位到每一行的等号上,这样方便跳转到之后要替换的位置,也方便自己看进度。wveqqc""<Esc>PWWq 中,w 定位到第一个要添加引号的字符串,ve 将其选定,剩下的操作是录制一个宏,宏的功能是在选定内容左右添加一对引号,然后用 WW 跳转到下一个可能还需要替换的位置。后续的操作就是选定要添加引号的字符串,然后调用 q 宏,看起来步骤很多,但都是常规的操作,如果熟练的话,很快就完成了。vee 是选定两个单词,v$h 是选定到行尾,vfg 是选定到后边的 g,根据实际场景选就可以了。

在 Vim 中最重要的其实不是知道多少特定场景的技巧,而是把最基础的光标移动练熟了,尽量做到可以很快定位到某一个位置,这是提升效率的关键。

总结

本文举几个需要批量在某些字符串两端添加引号的例子,有些很容易解决,有些却很难处理。实际上我们平时会遇到的场景一般都比较有规律,并不需要因此大费周章。当然自己写代码或者文档时也需要注意,不要这个地方有空格,那个地方没空格,这个地方用单引号,那个地方用双引号,看起来舒不舒服不说,会为后续的处理制造很多麻烦。

文章目录