我最喜欢的两个 Vim 功能是能够将标准运算符应用于与正则表达式匹配的行,以及能够通过外部命令过滤选择或行范围的能力。但是这两种想法可以结合起来吗?
例如,我有一个用作实验室笔记本的文本文件,其中包含由一行短划线分隔的不同日期的笔记。我可以做一些事情,比如删除所有带有:% g/^-/d
的破折线。但是,假设我想调整所有实际文本行的大小,而不触及这些虚线。
对于单个段落,这将类似于 {!}fmt
.但是,这如何应用于所有非破折号段落呢?当我尝试看似合乎逻辑的事情时,只是将这两个与:% v/^-/!fmt
链接在一起,这是行不通的。(事实上,它似乎使Vim崩溃...
有没有办法将这两个想法连接起来,并且只将匹配模式的行(不)传递到像fmt
这样的外部命令中?
考虑:global
命令的工作原理。
:global
(和:v
)通过缓冲区进行两次传递,
- 首先标记匹配的每一行,
- 然后在标记的行上执行给定的命令。
因此,如果您能想出一个命令(无论是 Ex 命令还是命令行工具)以及可以应用于每个匹配行(和范围)的相关范围,那么您就有了赢家。
例如,假设您的文本是软换行的,并且您的段落只是不以减号开头的行,以下是重新设置段落格式的方法:
:v/^-/.!fmt -72
在这里,我们使用"当前行"的范围,从而通过 fmt 过滤每个匹配行.
。更复杂的范围也可以工作。例如,如果您的文本是硬换行的,并且段落被定义为"从以减号开始的行,直到下一个空白行",则可以改用以下内容:
:g/^-/.,'}!fmt -72
帮助主题:
-
:h multi-repeat
-
:h :range!
-
:h :range
一种方法可能是将命令应用于与模式"不包含破折号"匹配的行
我会尝试的解决方案是这样的(未经测试):
:g/v^(-+)@!/normal V!fmt
编辑我正在做一些实验,我认为递归宏应该适合您
首先设置nowrapscan:
set nowrapscan
防止递归宏执行的次数超出预期。
然后进行搜索:
/v^(-+)@!
测试按 n
和 p
是否适用于您的模式,并在需要时进行调整
之后,开始录制宏
qqn:.!awk '{print $2}'^M$
在这种情况下,我以awk为例.!
表示使用外部程序过滤当前行然后,要使宏递归,只需将字符串'@q'
附加到寄存器@q
let @q .= '@q'
并移动到缓冲区的开头以应用递归宏并进行修改:
gg@q
然后你就完成了。希望这有帮助