2

假设我有 5 行文本,如果我输入一些命令让 vim 处理每一行,Vim 将一个接一个地处理文本,第一行,第二行,...最后一行。我想要的是让 Vim 以相反的顺序处理我的文本。即先是最后一行,然后是第 4 行,最后是第一行。

为什么我需要这个?我有以下文字

1234567890
abc
123
def
1234567890
123456789

我想从包含 3 个字符的行中删除换行符(\n)。所以处理后,我会得到以下文字

1234567890
abc123def1234567890
123456789

好像小菜一碟,我用下面的命令

:%s/\v(^\w{3})\n/\1/

但我得到的是

1234567890
abc123
def1234567890
1234567890

为什么?我猜vim首先从第二行删除\n,然后这一行有文本abc123,现在vim不会在123之后删除\n,因为它现在不是3个字符,所以vim处理下一行def,并从中删除\n ,这就是我得到的结果。

如果 vim 可以从后向前处理,就不会发生这种情况,我可以得到我想要的结果。

顺便说一句,我可以通过其他方式得到预期的结果,我只是想知道这是否可能。

4

4 回答 4

2

可以使用perl实现:

while (<>) {
  chomp if (/^...$/);
  print;
}
于 2013-04-03T07:00:18.343 回答
2

显式地向后循环行的范围(例如视觉选择的行),然后在每一行上执行命令。我在:join这里使用了而不是:substitute换行符:

:for i in range(line("'>"), line("'<"), -1)| silent execute i . 'g/^\w\{3}$/join!' | endfor
于 2013-04-03T07:16:09.760 回答
1

:global在这种情况下,使用该命令连接行更容易。

:g/^\w\{3}$/normal! gJ

该命令gJ将当前行与下一行连接起来,而不插入任何空格。上面的全局命令调用gJ每行只包含三个字符。它通过在执行操作之前首先标记所有匹配项来工作,因此避免了循环问题。

于 2013-04-03T07:17:09.017 回答
1

这条线应该做你想做的事:

:%s/\v(\_^\w{3}\n)+/\=substitute(submatch(0),"\n","","g")/

如果您想使用外部命令更简单,例如 awk,您可以:

%!awk '{printf "\%s", length($0)==3? $0:$0"\n"}'
于 2013-04-03T08:48:39.360 回答