[VimGolf] 在每一个非空行的行首添加一个 *
我发现 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 分,一点提升也没有,而且看起来用 :v
加 s
好像没办法更高效了,还得换思路。
第三次尝试
感觉用 :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 分,:g
加 s
肯定是不行的。
: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 分,简单明了,灵活性也更强。
本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。