我的问题是:我知道如何反转文件中的所有行(:g / ^ / m0等方式),但是有一种方法可以使文件中的每4行反转,从而使
成为
line1
line2
line3
line4
line5
line6
line7
line8
...
您可以假定此类文件中总是存在4行的精确倍数。
#1 楼
Vim Wiki上解释的命令:Reverse
可以用于此目的(您可以将其包括在.vimrc
中以使其永久化):每四行运行一次命令:command! -bar -range=% Reverse <line1>,<line2>g/^/m<line1>-1|nohl
说明:
qm
:正常情况下为“ q”模式开始(并停止)在给定寄存器(在这种情况下为寄存器'm',但可以是其他任何字母)中记录宏。V
:进入可视模式并选择当前行3j
:将可视选择范围扩展到下3行:Reverse<cr>
:在选定的行上运行“反向”命令(<cr>
代表Enter键)4j
:转到下一个未更改的行q
:停止记录宏1000@m
:运行在寄存器“ m”处记录的宏1000次(您可以增加如果文件大于4000行,则使用此数字)编辑:
在注释中提到,您可以使用递归宏而不是使用计数:
qmV3j:Reverse<cr>4jq
1000@m
qM
:如果为q
指定了寄存器如果是大写,则宏将附加到寄存器(当您意识到错过复杂宏的最后步骤时也很有用)。@m
:在寄存器m
上运行宏q
:停止追加宏尽管它是作为宏创建的,但是如果它是工作流程中的常见任务,则可以为此创建命令:
qmV3j:Reverse<cr>4jq
qM@mq
@m
function! Reverse4()
/ endfunction
:定义新功能let reg_m = @m
:保存寄存器m
的当前内容let @m = "<c-r><c-r>m"
:将宏插入寄存器m
中-请注意<c-r>
是Ctrl + r的vim表示法,您应该键入它,而不是复制/粘贴,因此您的行将类似于let @m = 'V3j:Reverse^M4j@m'
,并且将包含特殊字符( ^ M)normal! @m
:正常命令在正常模式下输入时会运行其参数,因此它将运行递归宏。let @m = reg_m
:恢复寄存器m
的内容,因此您不必记住该功能正在使用该寄存器,而不必使用它command! Reverse4 call Reverse4()
:为此功能创建新命令根据您的需要,您可以对其进行增强,例如:将参数传递给命令和函数,以便它适用于任意数量的行,而不是固定在4行的组中。
评论
除了使用1000 @ q hack外,您还可以使用递归宏:qmqqm ... @ mq @ m。
–门把手
16年1月29日在13:06
当我尝试运行“ qmV3j:Reverse
–ableablewasiereisawelba
16年1月29日在16:51
啊没关系。我知道了-我不应该在“ qmV3j:Reverse
–ableablewasiereisawelba
16 Jan 29 '17:27
@ablewasiereisawelba要使该命令永久可用,只需编写line命令! -bar -range =%反转vimrc中某处的
– saginaw
16年1月29日在17:33
@saginaw哦,我没有意识到这很简单。谢谢。
–ableablewasiereisawelba
16年1月29日在17:39
#2 楼
与所有重复操作一样,如果您可以通过基本的编辑操作执行一次操作,那么可以通过记录宏轻松地执行多次操作。(在这种情况下,我将使用递归宏,但是您可以录制一个非递归的音频,然后通过锤击
@@
或使用计数来多次播放。) br /> gg
:移至文件的开头。qqq
:清除寄存器q
。我们将在第5步中看到为什么这样做是必要的。通过手动删除和粘贴它们。 (乍看之下可能看起来很复杂,但是不会被欺骗。这是您在qq
的前5分钟左右学到的非常基本的知识:ddjjpkddkkPjddpjj
,vimtutor
,j
,k
,dd
)p
:调用宏!此时,寄存器P
不包含任何内容(因为我们已在步骤2中将其清除),因此将不会发生任何事情。@q
:停止记录宏。q
:重播递归宏根据需要进行多次。NB如果文件包含的行数不能被四整除,则以上内容将无法产生预期的结果。为了在没有四行的情况下尽早停止宏,我们需要执行Vim正常模式命令,该命令将失败,然后在步骤4中开始应用编辑。我们可以通过尝试向下移动来完成此操作。在我们开始四处移动之前,先行三遍(然后备份):
q
因此:
ggqqqqqddjjpkddkkPjddpjj@qq@q
评论
为什么要明确清除寄存器q?如果您仅记录到其中,无论如何都将被覆盖...。
–通配符
16 Jan 29 '14:34
@Wildcard因为它是一个递归宏,所以在您第一次调用寄存器q的内容时,它必须为空,否则会弄乱您的版本。
– saginaw
16年1月29日在14:39
非常好。我以交互方式尝试了此操作,而没有尝试键入命令的确切顺序,然后使用以下命令结束:
–通配符
16年1月29日在14:44
@ablewasiereisawelba,每次需要执行此操作时,我都可以在其中使用单行自定义命令-请注意,您不必每次都需要重新创建宏,因为可以存储它作为vimrc上的功能/命令。
–mMontu
16年2月1日在11:20
@ablewasiereisawelba我很高兴您发现“编辑”很有用!因为这是您的第一篇文章,也许您不知道StackExchange通知的工作原理:当您发表评论时,答案/问题的作者会收到通知;仅当您包含@
–mMontu
16年2月12日在10:12
#3 楼
您还可以使用Ex
命令(使用sed
作为外部过滤器)来执行此操作::%!sed -n 'h;n;G;h;n;G;h;n;G;p'
此版本将忽略(删除)4的倍数以外的任何多余的行。保持最后一组少于4行(反转),请使用:
:%!sed -n '$p;h;n;G;$p;h;n;G;$p;h;n;G;p'
此处
%
的意思是“缓冲区中的每一行。” !
命令的意思是“以指定的行作为输入运行以下命令,并用命令的输出替换指定的行。” (这称为过滤器;对于诸如排序之类的事情非常方便,例如:%!sort
将对文件中的所有行进行排序; :2,8!sort
将对第2-8行进行排序,依此类推。)sed
是流编辑器工具,可以在所有类似Unix的系统上找到。此处使用的sed
的关键概念是“模式空间”(默认情况下仅依次包含输入的每一行)和“保留空间”(您可以在其中使用sed
保留额外的文本,同时保留额外的文本)处理其他输入行)。-n
是sed
命令的一个选项,用于抑制其打印模式空间的默认操作(因为在这种情况下,我们只希望在明确声明时打印)。 $p
命令中的sed
表示“如果在sed
的输入的最后一行,则打印(图案空间)。” h
表示“保持当前位置“保持空间”中“模式空间”的内容,覆盖那里的所有内容。” n
的意思是“用输入的下一行替换'模式空间'的内容。” G
的意思是“附加到'模式空间':换行符,后跟'保持空间'的内容。” 总而言之,
sed
命令存储四行输出,在存储它们时将它们反转,然后打印它们。在第二个版本中添加的$p
命令可确保,如果到达文件的最后一行而不是四行的倍数,则仍会打印这些行。交互式方法仍不使用任何Vim特定功能,也不使用外部过滤器:
:4
转到第四行。
:.m -4 | +3m . | +2m . | +5
反转前四行(1-4),将光标留在第8行。
.m -4
将当前行移到四行的后一行(将光标移到移动的行上。)+3m .
将当前行之后3行的行移动到当前行之后,将光标留在移动的行上。 +2m .
当然工作原理相同。+5
将光标从其所在位置向下放置五行。根据需要重复。
在Vim中,可以使用
@:
重复整个命令,然后再次使用@@
重复整个命令。在POSIX vi
或ex
中,您需要将:.m -4 | +3m . | +2m . | +5
插入为一行文本,将其删除到命名缓冲区(寄存器),然后执行该命名缓冲区(寄存器)。因此在
ex
模式下,仅使用POSIX指定的功能以交互方式反转行,并以17行文本开头:Entering Ex mode. Type "visual" to go to Normal mode.
:0a # Append following text after "line 0" (i.e. insert at start of file).
.m -4 | +3m . | +2m . | +5
. # End text insertion
:d k # Delete that line to register k
line1 # This is a printout of the current line
:4 # Move to line 4
line4
:@k # Execute register k to reverse lines 1-4
line8
:@@ # Execute register k again
line12
:@@ # Execute register k again
line16
:@@ # Execute register k again
line17
:%p # Print the whole buffer (just to see what was done)
line4
line3
line2
line1
line8
line7
line6
line5
line12
line11
line10
line9
line16
line15
line14
line13
line17
:wq # Save and quit
进一步阅读:
用于
ex
的POSIX规范用于ex4310的POSIX规范
有实际用途吗?
评论
您能否再说明一下您的解决方案?
–vappolinario
16年1月29日在12:04
@vappolinario,我添加了一些进一步的解释。有帮助吗? :)
–通配符
16年1月29日在12:35
哇,答案很长。 :)实际上,我已经sed了,但是我只是将它与一个简单的脚本一起使用,该脚本在某个地方(可能在此板上)找到了,这是我遇到的一个问题的解决方案。但是,当我尝试运行建议的行时,它说“ sed”未被识别为内部或外部命令,可操作程序或批处理文件。我不确定是否需要在vim文件夹中进行sed操作。
–ableablewasiereisawelba
16年1月29日在16:58
@ablewasiereisawelba,如果您在Windows机器上运行且未使用Cygwin(或MobaXterm或类似产品),则可以尝试我提供的另一种方法:4G:.m -4 | + 3m。 | + 2m。 | +5
–通配符
16年1月29日在17:20
@Wildcard哦,好的,我现在正在检查MobaXterm。 :)
–ableablewasiereisawelba
16年1月29日在17:33
#4 楼
:g/^/exe 'm .-' . substitute(line('.') % 4, '^0$', '4', '')
普通英语:对于每行,将当前行上移
lnum % 4
,除非lnum % 4 == 0
除外,在这种情况下,将当前行上移4
。行,将上述命令中的n
替换为4
。评论
非常好的单行命令。谢谢,djjcast。
–ableablewasiereisawelba
16年2月2日在17:37
评论
关于“ p.s”:如果在一行的前面插入4个空格,它将被解释为代码(您可以选择文本并使用顶部的格式按钮)。您可以在顶部的询问图标上找到更多详细信息。