目录

有多少种方式可以在vim 中插入行号

1 在文本中插入行号

最近有朋友提到某编辑器有一个可以插入行号的插件,问Vim有没有办法可以在文章中插入行号。%$^&*#8~#$@#!……让我们看一下有多少种方式可以在vim中插入行号或数字序列!

建议看一下Vim官网的这篇文章。里面一部分内容与这篇是重叠的。不过这篇是中文的XD。

我们的目的是在当前编辑文中的每一行前面加上行号或数字序列并用空格分隔,如:

这是第一行
这是第二行
	
这是第四行

在插入行号后将成为:

1 这是第一行
2 这是第二行
3
4 这是第四行

但有时我们需要对部分行编号。下面的例子是对第二行以后的所有非空行依次编号:

这是第一行
1 这是第二行
	
2 这是第四行
3 这是第五行

为了区别行号,我这里就称之为数字序列。

进入正题。

1.1 使用line()函数

相信这是大多数人第一个想到的解法了——使用line()函数产生行号用:s命令插入行号。

" 为所有行加上行号
" 使用合适的范围或者正则表达式就可以限定作用的范围。
:g/^/ s//\=line('.').' '/

优点是简单易用。缺点是不够灵活,只能用以显示指定行的行号。

1.2 使用ex命令

vim提供了一些可以打印行号的ex命令,如,“=”, “p #” 和“#“。为了捕捉Vim的命令输出,我们用redir命令。

" 为前30行加上行号
:redir @a | 1,30# | redir END
:1,30d | put! a

逻辑上很容易理解:1,30#显示前30行及其行号。保存到寄存器a中,删掉前30行,再贴上寄存器的内容。

没什么明显优点的一种方法。缺点同上。如果不是更改当前编辑区的内容而是直接保存到新文件的话,这种方法就比其他的方法方便。

1.3 使用range()函数

range()是个新的函数,用来产生包含数字序列的列表。当然也可以用来生成行号:

" 为前30行加上行号
:for i in range(31)
:call setline(i,i .' '. getline(i))
:endfor

对range(),setline()的用法见帮助文档。

range()函数相对前面的2个解法而言要灵活许多,除可用以表示行号,也可以用来编数字序列,相应地也要求一些编程基础。

1.4 加法运算

这是也是简单灵活的一种解法。好吧,也许大家第一个想到的解法不是使用line()函数。

" 为所有行加上行号
:let i=1
:g/^/ s//\=i . ' '/ |let i=i+1

注意:g后面的两条命令(:s, :let)一定要写在一起。这是比较通用的一种编号方式,可以应付大部分的编号问题。

1.5 使用<CTRL-A>

Vim提供了Ctrl-A和Ctrl-X来分别对光标下(或者光标右边第一个)数字进行增、减操作。按Ctrl-A一次可加一,按Ctrl-X则是减一。如果你用的是Windows,那很有可能Ctrl-A已被映射成全选了。输入

:nunmap <C-A>

使之恢复功能,当然你可以用:nnoremap重新映射到其他键。赶紧翻出文档吧:

:h CTRL-A
:h CTRL-X
:h unmap
:h o_v

先看一下,普通模式下的操作步骤:

上面添加空格是很重要的步骤(因为我们使用了yaw复制数字和空格),这里解释一下第三步:

`qq‘
开始录制宏,并保存到寄存器q中
`0‘
设定光标的位置到行首
`"aP‘
放上前面保存的序号和空格
`0^A‘
回到行首并按Ctrl-A加一
`"ayaw‘
复制当前数字和空格到寄存器A
`jq‘
移到下一行(这样我们才能确保28@q是对下面的28行进行操作而不是对当前行操作28),然后结束宏。

通过与:g指令配合可以对指定行编号。下面的例子对所有以字母开头的行进行编号。为了说明方便我们直接对寄存器赋值,效果与上面普通模式下的操作是一样的。注意下面两例操作中的^A的输入方法与上面直接按组合键的方法有所不同,先按Ctrl-V(不行的话试Ctrl-Q),再按Ctrl-A:

" 先重置a寄存器。
" 再对所有以字母开头的行编号
:let @a='0 '
" 去掉了j指令
:let @q='0"aP0^A"ayaw'
:g/^\a/ norm @q

如果你用的分隔符不是空格,可以对它进行手工标记:

" 这个例子使用冒号作为分隔符
:let @a=0
:let @q='0"aPa:^[0^Amm"ayv`m'
:g/^\a/ norm @q

宏指令是Vi最有力的工具之一,在Vim中宏则比以往更强大。宏并非完成此工作最有效率的解法,但写宏的乐趣要比其他的脚本来得多得多。这个解法经过修改一样可以适用多种情况,缺点是在写出一个可行的宏之前要经过多次地调试。