Vim:用之前复制的一行替换另一行

154

我每天至少有一次遇到以下情况:

A: This line should also replace line X
...
X: This is line should be replaced

我认为我不能高效地执行那个任务。

我的做法如下:

  • 转到第 A 行:AG(用行号替换 A
  • 复制第 A 行:yy
  • 转到第 X 行:XG(用行号替换 X
  • 粘贴第 A 行:P
  • 移动到旧行:j
  • 删除旧行:dd

这样做的额外缺点是,行 X 现在在默认寄存器中,如果我发现另一行应该被替换为 A,则会很烦人。从其他寄存器中复制和粘贴("ayy"aP)使得这个简单任务变得更加低效。

我的问题:

  • 我是否错过了一个内置的 Vim 命令来替换之前复制的行?
  • 如果没有,如何绑定我自己的命令,以便将复制的行留在(或还原到)默认寄存器中?

2
这是我对Vim编辑模式的最大问题。我很想知道解决方案。 CUA编辑器区分剪切和删除,所以你只需剪切一些文本,然后可以进行删除和粘贴。但在Vim中,任何删除操作都会破坏已剪切的文本。你最终将使用比其他编辑器更多的按键。 - Mud
3
YankRing是一个Vim插件,它可以帮助你更好地管理剪贴板历史记录。使用YankRing,你可以轻松地浏览、搜索和粘贴之前复制的文本内容。这个插件还提供了一些其他的功能,例如删除历史记录中的条目、限制历史记录数目以及对不同种类的文本做出不同的处理。如果你经常需要复制和粘贴文本,那么YankRing可能是一个非常有用的工具。 - ajreal
2
@sehe 我完全知道寄存器,但每次剪切/粘贴操作都要增加4个按键,而且需要更多的预先考虑。当你正在进行大量编辑时,这个差距很快会累积。 - Mud
除了节省一些内存空间外,使用黑洞寄存器与使用其他寄存器相比是否有优势?我认为,如果您不从任何寄存器中读取数据,那么任何寄存器都可以成为黑洞寄存器。 - sleblanc
17个回答

159

Vp:选择一行,粘贴上次复制的内容。


10
“VP”同样有效,这非常方便,因为你可以在整个序列中保持Shift键。 - George Hilliard
40
非常巧妙的技巧,但值得注意的是一个(可能)重要的警告:这会导致“yank”寄存器更新为被覆盖的行的内容,因此它可能不适用于某些任务 - 例如,如果您想将同一行覆盖到多个目标上。 - underscore_d
12
@underscore_d,如果你使用 V"0p 命令,它会很好地运行,该命令会从最后一次拷贝的寄存器中粘贴。 - timblaktu
@timblaktu 你能解释一下 V"0p 是什么意思吗?V 进入可视行模式,p 用于粘贴。那么 " 和 0 分别代表什么呢?谢谢。 - theprogrammer
4
"代表寄存器,0代表yank寄存器。因此,使用"0告诉p从yank寄存器中粘贴内容。该寄存器与默认寄存器不同,当执行Vp命令时会覆盖默认寄存器(yank会同时填充默认寄存器和其自身的寄存器)。 - C S
我不喜欢这个解决方案,因为它只能使用一次。在你刚刚粘贴的行被复制到寄存器并替换当前的yank之后,它就失效了。 - caylus

107

我的做法:

  1. 36G(将 36 替换为您要跳转到的行号)
  2. Y
  3. 70G(将 70 替换为您要跳转到的行号)
  4. Vp

您不必离开正常模式,但是会复制该行。但是,您可以使用 V"0p,这将始终将在第2步中复制的行放置。


14
@duddle:是的,Yyy 的同义词。 - icecrime
11
步骤1和2可以使用":ay [例如::20y]"结合起来完成。 接着使用Vp操作应该就可以了。 您无需转到行来复制它。 - Bharad
2
如果您使用ccCTRL+r0ESC覆盖额外的行,而不是V"0p,则所有以下行都可以用.(重复器)替换。 - Jordan Morris
1
使用 Y 剪切并使用 + 替换当前行而不影响缓冲区,使用以下 .vimrc 行::nmap + V"0p - soulshake
2
我不明白aG是什么意思?a会在光标后一个字符进入插入模式,而G只会插入一个大写字母G。 - vdegenne
显示剩余4条评论

47

这种方法的另一个缺点是,行X现在在默认寄存器中,如果我找到另一行应该被替换为A,那么这将变得非常麻烦。

要删除文本而不影响正常寄存器,您可以使用黑洞寄存器"_

"_dd

12
我在我的 .vimrc 文件中添加了一些映射,使得 ddd 命令总是使用黑洞寄存器,而 xxx 命令则执行大多数编辑器称之为“剪切”的操作(删除并保存到默认寄存器):noremap x dnoremap xx ddnoremap d "_dnoremap dd "_dd - IMSoP
2
我对在VIM中重新映射东西持谨慎态度,因为这可能在其他计算机上或IDE的VIM风格插件中并不容易。此外,如果你真的深入挖掘,VIM的设计师往往已经通过默认映射解决了问题。 - Jordan Morris

27

在参考使用 VpVP 粘贴到一行的答案上 -- 为了避免更改复制寄存器的内容,我发现最符合人体工学的命令就是:

VPY


1
这是最简单的解决方案,可以保持复制的内容不变。非常感谢! - heylookltsme

14
  1. yy
  2. j(移动至要替换的行),然后
  3. Vp(大写的v,然后p,将替换为复制的内容)

1
太棒了!非常简短,使用可视模式轻松选择多行。它还保持了粘贴缓冲区的完整性。当dd覆盖该缓冲区时真是令人恼火... - Aktau
1
@Aktau 这会导致缓冲区不完整。 - Jordan Morris

9
  1. 移动到第一行的开头。

  2. y, $ – 复制该行但不包括末尾的换行符。

  3. 移动到目标行的开头。

    1. V, p – 仅替换一个目标行。

    2. c, c, Ctrlr, 0, Esc – 用原始的复制内容替换目标行。

  4. 移动到下一个目标行的开头。

  5. . – 重复执行第4.2步骤的命令。

注:

  • 4.1 是 y, $ 因为如果使用 y, yY,将会复制换行符,而 Ctrlr0 实际上会在目标行下添加换行符。

  • 4.2 替换了 V p,因为使用重复命令时,最后的操作是删除,所以 . 将只会删除一行。

  • 如果有人知道如何在 EX 模式(命令行)中发出“用寄存器替换当前行”的命令,请告诉我(并让我知道文档在哪里)。可能会有一个可重复的 EX 命令比4.2更快,且不具备换行符的限制。


1
在这里,步骤 4.2 是关键,因为现在您可以像步骤 4.3 中的点命令一样重复整个过程。这就是 vim 的全部! - JESii
1
我不明白这个。'AG'会将我的制造者放在行末,进入插入模式并输入'G'。我哪里理解有问题? - gustafbstrom
@gustafbstrom 公正的批评 - 抱歉,A应该代表行号,但我没有指出来。已经编辑过了。 - Jordan Morris

9
我会使用命令行模式(例如)并执行以下两个命令。
:XmA
:Ad

这只是将X行移动到A行下方,然后删除A行会将该行上移。

例如:

:7m3
:3d

你能举个例子吗?例如,当我键入50Gm30G时,Vim会跳转到第50行并滚动到底部,然后就这样了。此外,对于A=50或A=50G,:Ad不起作用。 - crispy

8

您还可以做:

Vy (in normal mode at the line you want to copy)
Vp (in normal mode at the line you want to replace)
  • 不会创建空格或换行。
  • 光标位于复制文本的开头。

相同的键可以用于复制/粘贴多行。

V (in normal mode at what you want to yank)
(use jk to move the selection)
y (to yank the selection)
V (in normal mode at where you want to paste)
(use jk to move the selection)
p (to replace the selection with the yanked lines)

5

您可以在可视模式下使用此功能。

  • 前往A行:AG
  • 使用可视模式选择该行:VESC
  • 前往X行:XG
  • 进入替换模式:S
  • 粘贴您复制的行:shift+insert(或其他用于从剪贴板粘贴的映射)。

啊,我不知道 VS。然而,你的步骤对我不起作用,因为我不会复制到我的操作系统剪贴板,这是我只能在插入模式下访问的唯一剪贴板。所以我必须先离开插入模式。 - crispy

5

以下是我的建议:

  • 将行A(其中A显然是行号)的开头移动到AG
  • 将该行复制到某个寄存器(例如a),不要换行。输入"ay$
  • 移动到插入行,XG
  • 替换该行,S
  • 从寄存器a中插入内容,Ctrl-Ra

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接