Vim 技巧:匹配数字递增
有时候会有将代码中的数字递增/递减的需求,一直没有找到相对简单优雅的做法。今天通过网络搜索加上幸运值暴增,感觉终于比较完善地解决了这个问题,遂作此文记录一下。
如果我们想将以下代码块中的所有数字,在原有基础上均递增两次:
my_array[1] = 0; my_array[2] = 0; my_array[3] = 0; my_array[4] = 0; my_array[5] = 0; my_array[6] = 0; my_array[7] = 0;
即变成以下这样:
my_array[3] = 2; my_array[4] = 2; my_array[5] = 2; my_array[6] = 2; my_array[7] = 2; my_array[8] = 2; my_array[9] = 2;
笔者以前的做法:如果仅有几处需要修改,那就直接跳转到数字处,按 Ctrl + a 或 Ctrl + x 完事。如果修改之处较多而且数据格式比较规整,那就录制一个宏然后执行。不过格式规整的情况太少了,所以大部分情况下还是用第一种方法,有时候就得跳转多次并重复按 Ctrl + a ,觉得有点烦。
搜索之后得出的 第一个解决方案 1 :
将光标移到第一行的 1 处,按 Ctrl + v 进入 Visual Block 列模式,然后选择接下来的几行,最后按 Ctrl + a 。哈哈,变成了 2 3 4 …8 这样的。耶!一次性完工。(汗!还是平时遇到规整格式的情况太少,竟然不知道 Ctrl + a 可以和列模式混合使用。)接下来就好办了, gv 重复上一选区,再按一次 Ctrl + a 就 OK 了。不过这事还有更简单的方法——直接按 . 重复上一次操作,都不用进入选择模式。简直不要太方便!再将后面的 0 列如法炮制,即可打完收功。
还可以在按 Ctrl + a 之前,按个 g 键,这样递增数就与其所在行数相关了。比如上面的 0 列这样操作以后,就变成了 1 2 3 …7 的递增数列。
my_array[3] = 1; my_array[4] = 2; my_array[5] = 3; my_array[6] = 4; my_array[7] = 5; my_array[8] = 6; my_array[9] = 7;
这就很强悍了,不必像有些教程里说的那样,需要 let i=1
定义有点长的函数才能产生递增数列。貌似可以用这种方法给代码增加行号了?
不过该方法还是有不少限制的——仍然面临数字格式规整的问题。如果上面的数字出现两位数甚至浮点数,这时就无法用列模式选中,自然也就无法按预想进行递增。
my_array[1] = 0; my_array[2] = 0; my_array[3] = 0; my_array[41] = 0; my_array[51] = 0; my_array[61] = 0; my_array[71] = 0;
按照以上方法操作后变成:
my_array[3] = 2; my_array[4] = 2; my_array[5] = 2; my_array[61] = 2; my_array[71] = 2; my_array[81] = 2; my_array[91] = 2;
显然与最初预想的“自增两次”是不一致的。如果想用列模式操作,则需要将上面的代码在个位数上对齐:
my_array[1] = 0; my_array[2] = 0; my_array[3] = 0; my_array[41] = 0; my_array[51] = 0; my_array[61] = 0; my_array[71] = 0;
然后就可以继续使用上面描述的方法了。不过递增完最好把 1~3 行前面的空格去掉,有些语言可能会报错。
第二种方法 是使用 Vim 的正则替换功能。实际上笔者之前曾尝试过该方法,不过以失败告终。当时写的替换语句是这样的: :%s/\d\+/\0+2/g
。按我的料想, \0
是匹配的分组,在它上面直接 +2
不就好了?然而经实际测试并不行。事情的解决是发呆时抱着寻宝的想法打开 Best of Vim Tips ,一眼瞥见了那一行:
" decrement numbers by 3 :%s/\d\+/\=(submatch(0)-3)/
再仔细一看,可不正是我想要的正则替换?大喜过望,经实际试验果然如此!第一种方法所说的步骤,实际上只需选中代码块然后执行一条正则替换语句:
:'<,>'s/\d\+/\=(submatch(0)+2)/g
以前正则替换失败的症结在于并不知道 submatch()
这个内置函数。通过 :h submatch()
查看,该函数用来返回替换操作中第 n 个匹配字符串,而且以上命令中 submatch 的外层括号其实可以去掉。于是最终变成这样:
:'<,>'s/\d\+/\=submatch(0)+2/g
命令的其它部分则比较容易理解: '<,>'
代表选区范围, \d\+
匹配一个或多个数字, \=
表示接下来的是一个函数/表达式。
这种方法的优势在于没有格式规整的要求,且操作灵活性特别高,可充分利用正则表达式匹配功能。而且它已经不仅局限于数字递增了,可以用于字符串拼接等。
说来惭愧:尽管收藏 Best of Vim Tips 已经很久,却从来没有完整地看过它的每一条技巧,顶多是无聊时翻一翻。以前折腾了好半天还不成功的问题,今天就这么简单解决了。有时间还是得把这些技巧系统完整的过一遍,Vim 内置函数如有时间的话也很有必要挨个看一看。
文章链接:https://macplay.github.io/en/posts/vim-ji-qiao-pi-pei-shu-zi-di-zeng/
发布/更新于:
版权声明:如无特别说明,本站文章均遵循 CC BY-NC-SA 4.0 协议,转载请注明作者及出处。