在可视选择的每一行上使用Vim宏

99
我希望能在所选内容的每一行上运行宏,而不是在头脑中总结行数。例如,我可能会编写一个宏来转换以下内容:
Last, First

介绍

First Last

我希望它能够在所有这些行上运行:

Stewart, John 
Pumpkin, Freddy
Mai, Stefan
...

有什么想法,Vim专家?

编辑:这只是一个例子,显然可以用正则表达式轻松解决,但还有其他不太容易的情况,我更喜欢使用宏。


1
说实话,我可能会用正则表达式来完成这个特定的任务。但对于更复杂的情况,这个问题仍然是有效的。 - Jamie Wong
为什么使用vim?在我看来,sed更加合适。 - kokosing
9
为什么要退出编辑器,用一行正则表达式来编辑文本? - Stephen
1
好的,你已经明白了 ;) - kokosing
3个回答

177

假设你有一个在单行运行并保持不变的宏q。那么你可以使用以下方法在选择区域内的每一行上运行它:

%!}q

:'<,'>normal @q
(如果您已经选择了一组行,请按下冒号键,命令行将显示“:'<,'>”)
例如,以下宏将大写每个单词但第一个以外的所有单词:
:let @q="^dwgU$P"

所以在以下运行它(其中+行是选定的)

 0000: a long long time ago
 0001: in a galaxy far away
+0002: naboo was under an attack
+0003: and i thought me and qui-gon jinn
+0004: could talk the federation in
 0005: to maybe cutting them a little slack.

使用上述normal @q命令,会产生以下结果:

 0000: a long long time ago
 0001: in a galaxy far away
 0002: naboo WAS UNDER AN ATTACK
 0003: and I THOUGHT ME AND QUI-GON JINN
 0004: could TALK THE FEDERATION IN
 0005: to maybe cutting them a little slack.

@Roger Pate:如果你想把它打高尔夫球,那么是的 :) - rampion
1
@rampion:你的命令里有错别字吗?对我来说只有这样才能正常工作: :'<,'>normal! @q - oliver
3
@oliver:请检查你的键位映射,可能已经将 @q 进行了重新映射。根据 :help normal 中的说明:"如果使用 [!],则不会使用映射"。 - rampion
2
@rampion:该死...你是对的!我使用yankring,显然存在问题: _...您无法使用“:normal @a”执行宏。目前仍不可能,但您可以使用“:normal! @a”来执行它_(来自yankring的帮助文档) - oliver
1
我个人喜欢在可视模式下这样映射 @vnoremap @ :normal @。这样你仍然可以像预期的那样执行 @a(尽管之后你必须按回车键 :( )。 - LondonRob
显示剩余2条评论

20

选择行后按下:进入命令模式。Vim将自动填写'<,'>,该范围将限制为所选行。对于您的示例,您可以使用:s命令进行交换:

:'<,'>s/\(\w\+\), \(\w\+\)/\2, \1/

在可视化选择中,将每一行由逗号分隔的两个单词交换。

您还可以像其他书签或行位置一样使用'<'>,例如作为移动命令的一部分,在正常模式下d'<将删除从当前光标位置到可视选择中第一行的开头。即使该块不再被视觉突出显示,标记仍然有效。

如果您想在每行上重放记录的宏,则需要使用: normal命令执行该宏。不幸的是,: normal命令不会对一系列行起作用,但您可以使用: global命令解决这个问题。这将在与正则表达式匹配的每一行上运行一个: ex命令,因此您可以执行以下操作:

:'<,'>g/^/ norm @a

解释:

:'<,'>       for every line in the visual block
g/^/         on every line that matches the regex /^/ - i.e. every line
norm         run in normal mode
@a           the macro recorded in a

这比被接受的答案更好,因为它支持添加新行的宏。 - Jan Warchoł
@Dave, Kirby 或许将 ^ 替换为 . 会更好,这样宏只会在有文本的行上运行,不是吗? - SergioAraujo

1

您可以将以下功能添加到您的~/.vimrc文件中,或者只需在浏览器上复制它并运行:@+

fun! RunMacroOverSelection(macroname)
    execute "'<,'>normal @". a:macroname
endfun
com -nargs=1 Rover :call RunMacroOverSelection(<f-args>)
nnoremap <leader>r :Rover<space>

优点是您可以在视觉选择上应用任何宏。您需要将宏字母作为参数提供,例如:
:Rover a

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接