类似于https://vi.stackexchange.com/a/818/227的答案,您可以使用global命令。
使用它,您可以指示vim搜索与模式匹配的行,然后在其上执行命令。
对于您的情况,您希望将文本添加到以“ Level N:”开头的行之前,因此我们的全局命令可以是
:g/^Level \d:/{COMMANDS}
使用替代命令(正则表达式替换)作为命令
命令更加有趣。我通常喜欢对正则表达式进行替换,因为这样易于使用变量。
您的问题的例子
:let i = 1 | g/^Level \d:/s/^/\=printf("%02d ", i)/ | let i = i+1
怎么运行的
在替换命令的替换部分中可以是一个表达式。
我们要做的第一件事是将变量设置为i
起始数字。我选择了1,但任何数字都可以。let i = 1
然后,我们运行全局命令,该命令将我们设置为在匹配的行上执行操作。 g/^Level \d:/
我们将使我们的全局命令插入值,并使用替换命令和let命令增加计数器。 s/^/\=printf("%02d ", i)/ | let i = i+1
替换命令的正则表达式找到该行的开头^
并将其替换为表达式,而我们的表达式将是格式化打印的结果。像C语言一样,vim的printf带有格式设置参数。%02d
表示将参数转换为十进制数d
,至少占用2个空格,2
并填充0 0
。有关详细信息和其他转换选项(包括浮点格式),请参见:help printf
。我们给printf我们的计数变量i
,它给我们01
第一次,02
第二次等。替换命令使用它来替换行的开头,从而有效地将printf的结果插入开头。
请注意,我在d:之后放置了一个空格"%02d "
。您没有在问题中提出要求(并且我没有看到示例输出),但是我怀疑您想将数字与单词“ Level”分开。从给printf的字符串中删除空格,以使插入的数字紧靠在Level中的L旁边。
最后,let i = i + 1
每次替换后,我们的计数器都会增加。
这通常可用于用任意功能数据替换与其他条件匹配的部分线。
使用组合的普通命令
这对于简单的插入或复杂的编辑很有用。像替换一样,我们将使用global进行匹配,但是我们将执行一系列操作,就像由用户键入内容一样,而不是使用正则表达式替换。
您的问题的例子
:let i = 1 | g/^Level \d:/execute "normal! I" . printf("%02d ", i) | let i = i+1
怎么运行的
所使用的值与替代项非常相似(我们仍在使用printf格式化我们的数字以使其用2位数字填充0),但是操作不同。
在这里,我们使用execute命令,该命令接受一个字符串并将该字符串作为ex命令(:help :exe
)运行。我们构造了一个字符串,该字符串将“ normal!I”与我们的数据结合在一起,第一次将是“ normal!I01”,第二次将是“ normal!I02”,依此类推。
该normal
命令就像在普通模式下一样执行操作。在此示例中,我们的常规命令是I
,它会插入到行的开头。如果使用过dd
它将删除该行,o
将在匹配的行之后打开一个新行。就像您I
在普通模式下自己键入(或执行其他任何操作)一样。我们使用!
after normal
来确保没有映射妨碍我们。请参阅:help :normal
。
然后插入的是我们的printf的值,如使用替代的第一个示例中所示。
此方法可能比正则表达式更奇特,因为您可以执行类似的操作execute "normal! ^2wy" . i . "th$p"
,该操作将转到文本的开头^
,向前移动两个单词2w
,拉动直到第i个“ h”字符y" . i . "th
,移至行的末尾$
并粘贴p
。
这几乎就像运行宏一样,但是实际上并没有用完寄存器,而是可以合并任何表达式中的字符串。我发现这非常强大。
每个级别都有自己的计数器的方法
您可能希望每个级别都有自己的计数器。如果您提前知道最大级别数,则可以执行以下操作(添加额外的代码来找到最大级别可能并不难,但是会使答案变得太长。这会变得很长)。
首先,让我们释放i,以防万一我们已经将其用作整数。我们无法将我转换为列表,我们必须以这种方式创建它。
:unlet! i
接下来,将i设置为包含级别数的列表。您在问题中显示了2,但假设其中有10个是有趣的。由于列表索引是基于0的,并且我不想像您的列表那样基于1进行校正,因此我们将只创建足够的元素(11),并且永远不要使用0索引。
:let j = 0
:let i = []
:while j < 11 | let i += [1] | let j += 1 | endwhile
接下来,我们需要一种获取级别编号的方法。幸运的是,替代函数也可以用作函数,因此我们将其命名为行并提取级别号substitute(getline("."), "^Level \\(\\d\\):.*", "\\=submatch(1)", "")
由于i现在是一个11 1
s 的列表(每个索引是该级别的计数器),因此我们现在可以调整上述两个示例中的任何一个以使用此替换的结果:
通过替代命令:
:unlet! i | unlet! j | let j = 0 | let i = [] | while j < 11 | let i += [1] | let j += 1 | endwhile
:g/^Level \d:/let ind=str2nr(substitute(getline("."), "^Level \\(\\d\\):.*", "\\=submatch(1)", "")) | s/^/\=printf("%02d ", i[ind])/ | let i[ind] += 1
通过普通命令:
:unlet! i | unlet! j | let j = 0 | let i = [] | while j < 11 | let i += [1] | let j += 1 | endwhile
:g/^Level \d:/let ind=str2nr(substitute(getline("."), "^Level \\(\\d\\):.*", "\\=submatch(1)", "")) | execute "normal! I" . printf("%02d ", i[ind]) | let i[ind] += 1
输入示例:
Level 1: stuff
Level 1: Stuff
Some text
Level 3: Other
Level 1: Meh
Level 2: More
输出示例:
01 Level 1: stuff
02 Level 1: Stuff
Some text
01 Level 3: Other
03 Level 1: Meh
01 Level 2: More