我发现 VimGolf 是个很好玩的游戏。简单说,这个游戏就是用最少的 Vim 操作次数完成指定的题目,而这个操作次数就是自己所得的分数。

我之后做一些题目,在这里记录一下自己的思考和改进的过程,尽量不参考别人的操作。当然实在想不出来还是需要参考的,只是“我的分数”只记录我没参考别人操作的分数。

题目链接

prepend * to every non-blank line

题目说明

在每一个非空行的行首添加一个 *

开始文件

This is a
very short

file, but it is 
still
full

of

surpises.

结束文件

*This is a
*very short

*file, but it is 
*still
*full

*of

*surpises.

最佳分数

10

我的分数

11

:%s/./*&<CR>ZZ

第一次尝试

我之前还尝试过几次分数更低的,就略过了。

最容易想到的是用 :s 替换指令来做,把非空行的行首替换成 *\ze 的意思是后续的内容搜索但不匹配,也就是不会被替换掉。

:%s/^\ze./*<CR>ZZ

这样会得 14 分,距离最高分数还有 4 分,差距不小。因为 \ze 就占 3 分,所以得改变思路。

第二次尝试

另一个思路是先用 :v 过滤掉空行(v/^$/),然后用 s 进行替换。

:v/^$/s/^/*<CR>ZZ

很巧,也是 14 分,一点提升也没有,而且看起来用 :vs 好像没办法更高效了,还得换思路。

第三次尝试

感觉用 :s 还有改进空间,想想怎么把 \ze 去掉。想到了可以用 & 指代之前匹配到的内容。

:%s/^./*&<CR>ZZ

不错不错,又降了 2 分,现在距离最高分数只差 2 分了。不过这个“只”感觉不大妙啊,还能减 2 分?

第四次尝试

我怀疑用 :s 没法再减分了,:%s/ 是省不掉的,要从 ^./*& 里再减一两个字符,怎么想也感觉不靠谱。看来得尝试全部在普通模式完成了。

用宏呢?单行操作的话,I*<Esc> 就行,那录制一个宏 qqI*<Esc>q 就是 6 分了,加上退出文件 ZZ 的 2 分,就已经 8 分了。有办法在 4 分之内把这个宏作用在所有非空行吗?仅仅调用一次 @q 就占了 2 分,看来不现实。

那 10 分的操作肯定不是用宏实现的。有什么办法可以在普通模式同时对多行进行修改,还需要排除空行?看来有可能触及到我的盲区了。

突然发现上次的尝试还可以再减一分,里边的 ^ 是可以去掉的!

:%s/./*&<CR>ZZ

现在是 11 分了,还剩最后 1 分。

第五次尝试

感觉还得在这个基础上继续改,虽然好像不大可能。刚才想了下怎么能更快地退出,但没想到方法。把 ./*& 简化成三个字符的话,好像已经明摆着不可能了。这很像一个死胡同了。

刚才想到用 Ex 模式。

Q%s/./*&<CR>x<CR>

还是 11 分,好像和刚才的没什么区别。

又想了想用 :s,只比第二次尝试少 1 分,:gs 肯定是不行的。

:g/./s//*&<CR>ZZ

只用 :g 不用 s 呢?我没想出什么办法可以实现修改。

现在我有些怀疑有更快的退出方法。

先不和它较真了,看看其他题目。

第六次尝试

刚才去做了两个其他题目,都没有全靠自己做出来,看来这个也不可能了,学习下吧。

@Sakigw

<C-V>GyPgvr*ZZ

分析下这是什么操作。<C-V>G 是进入列可视模式选择第一列,yP 是复制第一列然后粘贴,这样非空行的第一个字符就被重复了一次。gv 是进可视模式选择上一次的选区,也就是第一列,r* 是把每列重复的第一个字符替换成 *。其中重点是 <C-V>GyP,巧妙地绕过空行的干扰。估计非常有经验的 Vim 用户才能想到这样的方法,我是甘拜下风了。

还有其他操作方法。

@TweetTontony

<C-V>GyP<C-V>Gr*ZZ

和上一个差不多,只是把 gv 换成了 <C-V>G,也就是又重新选择一下第一列,看起来更直观,但操作上没有上一个方便。

最佳操作

@Sakigw

<C-V>GyPgvr*ZZ

实用操作

:%s/./*&<CR>ZZ

11 分。

只多了 1 分,简单明了,灵活性也更强。

文章目录