如何反转行的顺序,使第一行显示在末尾,最后一行显示在前?(可能是缓冲区中的所有行,地址范围或逐行可视模式选择。)
我想改变
rat
ox
tiger
⋮
dog
pig
进入
pig
dog
⋮
tiger
ox
rat
无需借助外部命令如tac
。
如何反转行的顺序,使第一行显示在末尾,最后一行显示在前?(可能是缓冲区中的所有行,地址范围或逐行可视模式选择。)
我想改变
rat
ox
tiger
⋮
dog
pig
进入
pig
dog
⋮
tiger
ox
rat
无需借助外部命令如tac
。
Answers:
全球力量将在这里发挥作用:
:g/^/exe "normal ddggP"
或者,更简单地说(感谢@tommcdo)
:g/^/move 0
第一行将匹配每一行,并针对每一行将其删除并将其粘贴到文件的顶部。在文件中移动时,它会反转文本。
第二个类似地匹配每一行并将其移到文件顶部。
注意:这两种方法都适用于整个文件,并且不适用于反转行的子集。请参阅Ingo Karkat的答案以获取适用于一定范围的解决方案。
描述:
g
全局命令
/^/
匹配任何以开头开头的行(即所有行)
exe
执行以下字符串
"normal
执行普通模式命令
dd
删除行
gg
移动到
P
当前位置上方文件粘贴的顶部
move 0
将当前行移至第0行(将其置于位置1或文件的第一行)
:normal
命令,我们可以使用Ex命令:move 0
,它将行移动到缓冲区的开头。
:execute
,当命令需要动态构建,如只需要:execute 'normal' g:user_command
。
:execute
因为我经常会在现有的Ex命令之后追加其他Ex命令,并且相对于:exe
以后再返回并插入它,对我来说更方便。不幸的是,这个习惯渗入了这个答案中,但并没有太大用处。
:execute
:由于它使用字符串,因此它为普通模式命令的结束位置提供了清晰的描述,即使我没有构造字符串,与查找相比,查找平衡的引号也更容易<esc>
或终止该模式的任何方法。同样,这是个人喜好和习惯。:-)
:9,11g/^/move 8
... ...最后一个数字必须是范围的开始减去1(根据Ingo的答案改编)。
这行代码(为您~/.vimrc
定义)定义了一条:Reverse
命令;您也可以:global
直接使用该零件,但是(的语法:move
(将行反复迭代到范围的开始之前,从而将其反转)的语法)很难记住:
:command! -bar -range=% Reverse <line1>,<line2>global/^/m<line1>-1
<line1>
&<line2>
必须在一定范围内进行此项操作,即:(:7,9Reverse
它们是command
,不是global
or的特征move
)。更简单的方法:command! -bar -range=% Reverse :global/^/m 0
也可以使用,但仅适用于整个缓冲区...
纯Vim:
:g/^/m0
说明:
根据
:help multi-repeat
,:g
它的表亲:v
以两次通过的方式工作。
:g
标记的第一遍每行都匹配{pattern}
,而第二遍(显然是从文件的开头开始并进行到结束)执行[cmd]
。上面的用法:g
利用了处理行的顺序(虽然没有技术上的保证,但可能还可以)。它的工作方式是首先标记每一行,然后将第一条标记的线移动到文件的顶部,然后将第二条标记的线移动到文件的顶部(在先前移动的行上方),然后是第三条标记的行(同样在先前移动的行上方)行),以此类推,直到文件的最后一行移到顶部,从而有效地反转了文件。
请注意,如果
:g
以从上到下的任何顺序处理行,则此命令将不起作用。
很少有使用外部命令的示例:
tac
(GNU coreutils的一部分- cat
反向):
:%!tac
tail
在BSD / OSX(不符合POSIX)上:
:%!tail -r
-r
-r选项使输入以相反的顺序逐行显示。检查:
man tar
有关更多详细信息。
有关更多想法,请参见:
:g/^/m0
一样:g/^/move 0
吗?
tac
)。但是我怀疑投票否定是因为重复了答案。
tac
OP提到了这一点,但是所有其他类似的问题无论如何都会重复出现,因此再次提到它是很好的。John从@tommcdo评论中获取了此cmd,我最初是从DerMike那里获取的,但我认为他只是从wikia中获取的,因此我对vim wikia表示了感谢,因此,由于解释是完全不同的,因此并不完全相同。
本着功能性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>)))
hlsearch
像:g/
其他答案中的命令那样突出显示内容(如果已启用)...但是性能可能会更差吗?因为它getline(1, line('$'))
获取了整个缓冲区在内存中。reverse()
似乎已经就位,因此应该只占用很少的内存...
根据Vim文档usr_12.txt-聪明的技巧
12.4反向行顺序
该
:global
命令可以与:move
命令结合使用,以将所有行移动到第一行之前,从而得到一个反向文件。该命令是::global/^/m 0
缩写:
:g/^/m 0
在
^
正则表达式的行(即使该行是空白)的开头匹配。该:move
命令将匹配的行移动到神话中的第零行之后,因此当前的匹配行成为文件的第一行。由于该:global
命令不会被更改的行号所困扰,因此请:global
继续以匹配文件的所有其余行,并将每行都放在第一行。这也适用于许多行。首先移至第一行上方并用标记
mt
。然后将光标移到范围的最后一行并键入::'t+1,.g/^/m 't