我想用制表符作为分隔符加入文件中每3行的内容,如何在 Vim 中实现?
虽然我知道宏机制,但我正在寻找更优雅的解决方法。
我会选择两个:help :normal
命令...
Append a tab to every line:
:%normal A^i
with the literal ^i
being obtained with <C-v><Tab>
.
Join every group of three lines:
:%normal 3J
%normal 3J
会将制表符替换为空格。 - Lieven KeersmaekersJ
可以去除缩进,但我的制表符在行末,因此不会受到影响。 - romainlgvim -u NONE
可以工作。很可能是 expandtab
的问题。 - Lieven Keersmaekers$ vim -Nu NONE
。 - romainl原来这个可行:
:g/\n/,+1s//\t
:global
将匹配缓冲区中的每一行(或者在你传递一个范围时,范围内的每一行)。
/\n/
是一个正则表达式,将匹配每一行,这里匹配的是换行符本身。我们可以使用像 /^/
(或者也许是 /./
或 /\S/
来匹配非空或非空白行),但在这里我们使用 /\n/
,因为我们希望在下面的 :s
中使用该模式,所以我们可以省略它并使用相同的模式。
然后,对于 :g
处理的每一行,我们使用该行到行 +1
的范围。这意味着两行,在这种情况下,当前行和下一行。由于我们想要连接三行,因此我们要替换两行上的行分隔符,从当前行到行 +1
。(您可以将其推广到使用需要连接的块中行数减去二再加上号码字符)。s//\t
,它等价于 s/\n/\t/
(使用空模式将匹配先前使用的模式,在这种情况下是传递给 :g
的模式)。这个 :substitute
将匹配的换行符替换为制表符,有效地连接匹配行。由于我们使用两行的范围,它将每次只能连接两行,有效地代替了两个换行符,这将连接三行。:global
的工作方式。它首先“标记”应该被处理的行,但如果该行不再存在,则跳过它。因此,虽然它将首先标记每一行,但当 :s
将第二行和第三行与块中的第一行连接起来时,对它们的标记就不再存在了,因此最终结果是 :global
不会再次尝试处理该行,并继续移动到下一个“标记”的行,这将成为下一个块的开始。.vimrc
中添加一个映射命令。
:%norm A<c-v tab><c-v esc>3J
。 - Lieven KeersmaekersJ
命令会删除制表符。解决方法是将我的答案中的<c-v tab
替换为一个唯一的字符/字符串,然后进行查找/替换。 - Lieven Keersmaekers