如何反转行的顺序,使第一行显示在末尾,最后一行显示在前? (可能是缓冲区中的所有行,地址范围或逐行可视模式选择。)

我要转换

rat
ox
tiger
⋮
dog
pig





pig
dog
⋮
tiger
ox
rat


无需借助诸如tac之类的外部命令。

评论

对这个问题有更好标签的建议吗?

也许是新的“ pure-vi”或类似标签?我已经看到几个可以从标记中受益的问题,这些标记表明不希望使用任何外部工具。我应该在Meta上问这个问题吗?

@Carpetsmoker(以及其他对此感兴趣的人)的标签问题现在位于metameta.vi.stackexchange.com/questions/1229/……

#1 楼

全局的力量将在这里起作用:

:g/^/exe "normal ddggP"


或者,更简单地说(感谢@tommcdo)

:g/^/move 0


第一行将匹配每一行,并针对每一行将其删除并将其粘贴到文件顶部。当它在文件中移动时,它会反转文本。

第二个类似地匹配每一行并将其移动到文件的顶部。

注意:这两个工作在整个文件上,将不适用于反转行的子集。请参阅Ingo Karkat的答案以获取在一定范围内工作的解决方案。

描述:

g全局命令/^/匹配任何以开头(即所有行)开头的行exe执行以下字符串"normal执行普通模式命令dd删除行gg移至文件顶部P粘贴在当前位置上方

move 0将当前行移至行0以下(将其置于位置1或第一行)的文件)

评论


代替:normal命令,我们可以使用Ex命令:move 0,它将行移动到缓冲区的开头。

–tommcdo
15年2月22日在20:21

另外:execute仅在需要动态构建命令时才需要,例如:执行'普通'g:user_command。

–tommcdo
15年2月22日在20:23

@tommcdo好点!我有使用:execute的习惯,因为我经常会在以后的现有命令之后附加其他Ex命令,并且对我而言,拥有:exe比以后再回去插入它更方便。不幸的是,这个习惯渗入了这个答案中,但并没有那么广泛。

– John O'M。
15年2月22日在20:34

有关我使用:execute的更多说明:由于它使用字符串,因此可以清楚地描述普通模式命令的结束位置,即使我没有构造字符串,也比起查找引号要容易得多。寻找或其他终止模式。同样,这是个人喜好和习惯。 :-)

– John O'M。
15年2月22日在20:41

这将在btw范围内起作用::9,11g / ^ / move 8 ...最后一个数字必须是范围的开始减去1(根据Ingo的答案改编)。

–马丁·图尔诺伊(Martin Tournoij)
2015年2月22日在21:05



#2 楼

这个单行代码(对于您的~/.vimrc)定义了:Reverse命令;您也可以直接使用:global部分,但是:move的语法(将行反复迭代到范围的开始之前,从而将其反转)并不容易记住:

:command! -bar -range=% Reverse <line1>,<line2>global/^/m<line1>-1


评论


作为读者的仅供参考,才能在一定范围内进行此操作,即::7,9Reverse(它们是命令的功能,不是全局功能或移动功能)。更简单的:command! -bar -range =%反向:global / ^ / m 0也将起作用,但仅适用于整个缓冲区...

–马丁·图尔诺伊(Martin Tournoij)
2015年2月22日在21:02



#3 楼

纯Vim:

:g/^/m0


解释:


根据:help multi-repeat:g及其表亲:v以两遍方式工作。

:g的第一遍标记与{pattern}匹配的每一行,而第二遍(显然是从文件的开头开始并执行到末尾)执行[cmd]。上面对:g的使用利用了行的处理顺序(虽然可以,尽管可能没有技术上的保证,但顺序还可以)。

它的工作原理是首先标记每行,然后移动第一条标记的行到文件的顶部,然后将第二个移到文件的顶部(在先前移动的行上方),然后将第三个标记的行(同样在先前移动的行上方),依此类推,直到文件的最后一行

请注意,如果:g以从上到下的任何顺序处理行,则此命令将不起作用。


来源:在vim Wikia上反转g的所有行和幂。

使用外部命令的几个示例:



tac(GNU的一部分) coreutils-cat反向):

:%!tac                                                                                                                                                                                                                                                              



BSD / OSX上的tail(不兼容POSIX):

:%!tail -r



-r -r optio n使输入按行反向显示。

检查:man tar了解更多详细信息。



有关更多信息,请参阅:



如何反转文件中的行顺序?在stackoverflow SE

如何反转文本文件的行?在stackoverflow SE

如何从文件向后打印行(不使用“ tac”)?在Unix SE上


评论


:g / ^ / m0是否与:g / ^ / move 0相同,这是约翰的答案?

–muru
2015年2月23日下午13:15

@muru我认为是这样,但是这一段更短(根据vim wikia),并且我添加了一些不同的解释,并提供了一些其他使用命令行的示例。

– Kenorb
2015年2月23日在13:17



是的,由于其他命令,我投票赞成(我也来发布了tac)。但是我怀疑投票否定是因为重复了答案。

–muru
2015年2月23日下午13:18

我知道OP曾提到过tac,但是所有其他类似的问题无论如何都会重复出现,因此再次提及它是很好的。 John从@tommcdo评论中获取了此cmd,我最初是从DerMike那里获取的,但是我认为他只是从wikia中获取的,因此我对vim wikia表示感谢,因此,由于解释是完全不同的,因此并不完全相同。

– Kenorb
2015年2月23日在13:23



它增加了更多的价值,因为它的版本要短得多,而且要有适当的说明,我也相信正确的消息来源。使用shell命令非常简单方便。如果人们不同意,他们可以简单地投票,没什么大不了的。

– Kenorb
2015年2月23日在16:03



#4 楼

本着VimL功能的精神:

:call setline(1, reverse(getline(1, line('$'))))




getline(1, line('$'))返回缓冲区中所有行的列表。 '$'line()的特殊参数,它指示缓冲区中的最后一行。

reverse(...)就地反转输入列表。如果不应修改输入列表,则需要使用reverse(copy(...))

setline(1, ...)用第二个参数替换了指定的行。当第二个参数是列表时,将与列表长度相同的行数替换为列表的内容。

如果您愿意,还可以定义一个包含范围的命令(默认为整个缓冲区%

:command! -bar -range=% Reverse call setline(<line1>, reverse(getline(<line1>, <line2>)))


评论


我喜欢这个答案。它也不会像其他回答中的:g /命令那样突出显示某些内容(如果启用了hlsearch)...但是性能可能会更差?由于它是getline(1,line('$'))获取内存中的整个缓冲区。 reverse()似乎就位,因此应该只占用很少的内存...

–马丁·图尔诺伊(Martin Tournoij)
15年2月23日在15:35

#5 楼

根据Vim文档usr_12.txt-巧妙的技巧


12.4反向行顺序

:global命令可以与:move命令结合使用来移动
第一行之前的所有行,导致文件反转。
命令是:

:global/^/m 0


缩写:

:g/^/m 0


^正则表达式与行的开头(即使该行为空白)。 :move命令将匹配的行移动到神话中的第零行之后,因此当前的匹配行成为文件的第一行。由于更改行号不会混淆:global命令
,因此:global会继续匹配文件的所有剩余行,并将每行都放在第一行。

这也适用于一系列线。首先移至第一行
上方,并用mt进行标记。然后将光标移到范围的最后一行并键入:

:'t+1,.g/^/m 't



#6 楼

使用相对数字。段落从第13行开始,垃圾邮件多了4行

 :13,13+4g/^/m12