在使用Vim时,我经常想用我刚拉出的代码块替换代码块。

但是当我删除要替换的代码块时,该代码块本身就会进入寄存器,它会擦除我刚刚删除的代码块。所以我已经养成了拉拽,然后插入,然后删除我不想要的东西的习惯,但对于大块的代码,这变得很混乱,试图保持插入的块和要删除的块分开。

那么,在Vim中替换文本的最灵活、最快的方法是什么呢?

是否有一种方法可以删除文本而不将其放入寄存器? 有一种说法吗?“替换下一个单词”或“替换到下一段” 还是使用多寄存器特性的最佳方式?


好吧,首先执行以下命令:

:h d

然后你会发现你可以删除到一个特定的寄存器。这样就不会改变默认寄存器中的内容。


对于你给出的具体例子,如果我理解了问题,那么这可能是可行的:

*Highlight what you want to put somewhere else
*delete (d)
*Highlight the code that you want it to replace
*paste (p)

如果你用的是Vim,你会有视觉模式,就像选择,但有分离模式,这是vi/ Vim的基础。

您要做的是使用可视模式选择源,然后弹出,然后再次使用可视模式选择目标范围,然后粘贴到默认缓冲区中的文本。

例子:

在文本文件中使用:

1| qwer
2| asdf
3| zxcv
4| poiu

使用以下序列:ggVjyGVkp,你将以:

1| qwer
2| asdf
3| qewr
4| asdf

解释道:

gg: go to first line V: start visual mode with whole lines j: go down one line (with the selection started on the previous lines this grows the selection one line down) y: yank to the default buffer (the two selected lines, and it automatically exits you from visual mode) G: go to the last line V: start visual mode (same as before) k: go up one line (as before, with the visual mode enabled, this grows the selection one line up) p: paste (with the selection on the two last lines, it will replace those lines with whatever there is in the buffer -- the 2 first lines in this case)

这有一点不方便,把最后一个块放在缓冲区,所以它不需要重复粘贴相同的东西,所以你会想要保存源代码到一个命名缓冲区,如“ay”(缓冲区称为“a”)和粘贴,如“ap”(但如果你在编程,你可能不想多次粘贴而是创建一个函数并调用它,对吗?对吧?)。

如果你只使用vi,那么你必须使用不可见的标记,而不是视觉模式,他标记更多关于这个,我很抱歉,但我不太擅长这种不可见标记的东西,我很受视觉模式的污染。


要删除某些内容而不将其保存在寄存器中,你可以使用“黑洞寄存器”:

"_d

当然,您也可以使用其他任何不包含您感兴趣的任何内容的寄存器。


在插入模式下删除的文本不会进入默认寄存器。


对于'replace word',请在正常模式下尝试cw。

对于“替换段落”,尝试在正常模式下使用cap。


是的。这比先删除“旧”文本稍微复杂一些,但是:

我从。开始。

line1
line2
line3
line4

old1
old2
old3
old4

shift+v选择line1, line2, line3和line4,然后用d命令删除它们

然后用同样的方法删除原来的1-4行。

然后,做

"2p

这将粘贴倒数第二行(第1-4行)。“3p会做倒数第三,以此类推。

最后得到

line1
line2
line3
line4

参考: 编号寄存器上的Vim文档


在windows版本中(可能也在Linux中),你可以使用“*y”(即在你的yank命令前加双引号和星号)插入系统的复制/粘贴缓冲区。

然后,您可以正常删除可替换的行,并使用“*p”粘贴复制的文本。


VIM文档:编号为0的寄存器包含来自最近yank命令的文本, 除非该命令指定了另一个["x]寄存器。

例如,我们删除“foo”和“bar”-注册表0仍然包含“foo”!因此“foo”可以使用“0p”来粘贴


有一个简单的映射是很方便的,它可以让你用缓冲区替换当前选择。

例如,当你把这个放在你的。vimrc

" it's a capital 'p' at the end
vmap r "_dP

然后,在复制一些东西到寄存器(即用“y”)后,你可以选择你想要替换的文本,并简单地敲击键盘上的“r”。所选内容将被当前寄存器替换。

解释:

vmap - mapping for visual mode
"_d - delete current selection into "black hole register"
P - paste

我把以下内容放在我的vimrc中:

noremap  y "*y
noremap  Y "*Y
noremap  p "*p
noremap  P "*P
vnoremap y "*y
vnoremap Y "*Y
vnoremap p "*p
vnoremap P "*P

现在我从剪贴板寄存器中插入和放入,而不必关心默认寄存器中发生了什么。另外一个好处是,我可以轻松地从其他应用中粘贴。我失去了一些功能,我知道(我不再能够管理剪贴板寄存器和默认寄存器的不同复制信息),但我只是无法跟踪多个寄存器/剪贴板。


我经常犯一个错误,当我执行命令“y'ank then '”_d'elete into a black hole then 'p'aste。我更喜欢'y'ank,然后删除我喜欢的,然后从0寄存器中删除' ' 0p',这是最后复制的文本被推入的地方。


为了强调EBGreen所说的:

如果在选择文本时进行粘贴,则所选文本将替换为粘贴的文本。

如果您想复制一些文本,然后将其粘贴到多个位置,请使用“0p”进行粘贴。编号为0的寄存器包含来自最近yank命令的文本。


此外,你可以列出所有寄存器的内容:

:registers

该命令使得在执行dbr应答之类的操作时更容易找出需要的寄存器。您还将看到/,%,#寄存器。(请参见:帮助寄存器)


最后,检查cW和cW来改变一个单词,包括和不包括尾随空格。(大写W包含标点符号。)


我在适当的情况下使用的两种解决方案是;

用Vims VISUAL模式突出显示你想要替换的内容,然后粘贴寄存器。

我使用这个主要是出于习惯,因为我只是在很久以后才发现第二个解决方案,例如

yiw   " yank the whole word
viwp  " replace any word with the default register

YankRing。有了这个插件,你可以使用键绑定<ctrl>+<p>来替换之前的编号寄存器与你刚刚粘贴的。

基本上你去粘贴,因为你会,但当你意识到你已经覆盖了默认寄存器,从而失去了什么你实际上想要粘贴你可以<C-P>找到和替换从YankRing历史!

其中一个肯定有插件…


对于Dvorak用户来说,一个非常方便的方法是将不需要的文本删除到“1寄存器”而不是“_黑洞寄存器”中,如果只是因为你可以在Dvorak中按“+ 1与相同的shift键和快速的小指运动,因为1是紧靠上面的键”(另一方面是PLUS d,这使得整个命令速度非常快)。

当然,1寄存器也可以用于其他事情,因为它很方便,但除非你有一个比替换文本更常见的目的,否则我认为它是一个很好的使用寄存器的方法。


我找到了一个非常有用的映射:

xnoremap p "_dP

删除的文本被放入“黑洞寄存器”,而被拉拽的文本仍然存在。

来源:http://vim.wikia.com/wiki/Replace_a_word_with_yanked_text


懒人的微创解决方案:

寄存器0总是包含最后一个yank (Rafael, alex2k8和idbrii已经提到过)。不幸的是,一直选择寄存器0会非常烦人,所以如果p默认使用“0”就好了。这可以通过在你的.vimrc中放入以下行来实现:

noremap p "0p
noremap P "0P
for s:i in ['"','*','+','-','.',':','%','/','=','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z']
    execute 'noremap "'.s:i.'p "'.s:i.'p'
    execute 'noremap "'.s:i.'P "'.s:i.'P'
endfor

第一行将每个p笔画映射到“0p”。但是,这将阻止p访问任何其他寄存器。因此,具有显式选择寄存器的所有p笔画都映射到for循环中的等效命令行表达式。P也是一样。

这样就保留了标准的行为,除了隐式的p和p笔画,它们现在默认使用寄存器0。

提示1:cut命令现在是“0d而不是d。但因为我很懒,这对我来说太长了;)因此,我使用以下映射:

noremap <LEADER>d "0d
noremap <LEADER>D "0D

默认情况下,先导键是\,因此您可以通过输入\d或\d轻松地剪切文本。

提示2:多键映射的默认超时时间非常短。您可能希望增加它,以便在选择寄存器时有更多的时间。参见:help timeoutlen了解详细信息,我正在使用:

set timeout timeoutlen=3000 ttimeoutlen=100

默认情况下,所有的yank和delete操作都写入未命名寄存器。然而,最近的yank和最近的delete总是存储在有编号的寄存器中(分开)。寄存器0保存最近的yank。寄存器1-9保存了最近的9个删除(其中1是最近的)。

换句话说,delete覆盖了未命名寄存器中最近的yank,但它仍然存在于0寄存器中。在其他答案中提到的黑洞寄存器技巧(“_dd)之所以有效,是因为它可以防止覆盖未命名的寄存器,但这不是必要的。

你可以使用双引号引用一个寄存器,所以可以像这样粘贴最近拉出的文本:

"0p

这是一个很好的参考:

http://blog.sanctum.geek.nz/advanced-vim-registers/


对于那些主要感兴趣的人,当您通过虚拟选择和粘贴替换文本时,不覆盖未命名寄存器。

你可以使用下面的解决方案,这是简单的,最适合我:

Xnoremap <expr> p 'pgv"'.v:register.'y'

以下是回答(和评论): 如何粘贴而不覆盖寄存器

它首先经过选区,然后再次选择带有新文本的选区(gv)。现在是上次在可视模式下使用的寄存器(通常是未命名的寄存器,但如果使用另一个寄存器进行粘贴,也会产生副作用)。然后将新值再次拉入寄存器。

PS:如果你需要一个更简单的变种,它也适用于intellj idea插件vim-simulation,你可以采用这个(缺点:覆盖未命名的寄存器,即使另一个寄存器被给出粘贴):

Vnoremap p pgvy


对于emacs-evil用户,可以在粘贴后触发函数(evil-paste-pop),并循环遍历杀死环中的先前条目。假设你将它绑定到<C-p> (Spacemacs中的默认值),你将按需要点击p后面的<C-p>。


我的情况:在普通模式下,当我使用x键删除字符时,这些删除会覆盖我的最新寄存器——当我想使用x删除字符并粘贴我在最近寄存器中的内容时(例如,在两个或多个位置粘贴相同的文本),这会使编辑复杂化。

我尝试了被接受的答案(“_d”)中的建议,但它不起作用。

然而,从https://vi.stackexchange.com/questions/122/performing-certain-operations-without-clearing-register上接受的回答/评论中,我把这个添加到我的~/中。vimrc,工作(你可能需要重新启动Vim):

nnoremap x "_x

也就是说,我现在可以执行普通的yank (y)、delete (d)和paste (p)命令——使用x删除的字符不再填充最新的寄存器。


对于那些使用JetBrans IDE (PhpStorm, WebStorm, IntelliJ IDEA)与IdeaVim。你可能会遇到像nnoremap d "_d这样的重映射问题,并使用它来删除一行dd。可能的解决方案:nnoremap dd "_dd

youtrack上有一些问题,请为它们投票: https://youtrack.jetbrains.com/issue/VIM-1189 https://youtrack.jetbrains.com/issue/VIM-1363


Vim有时更倾向于复杂性,而不是实用性,这给用户带来了应用寄存器来复制/删除操作的负担——通常情况下,用户只想粘贴复制的内容,而“忘记”删除的内容。

但是,与其与vim复杂的寄存器作斗争,不如让它们更方便:选择一个“默认”寄存器来存储最新的删除。例如,发送删除到d寄存器(让a-c打开以供特别使用;D是一个很好的助记符):

nnoremap d "dd           "send latest delete to d register
nnoremap D "dD           "send latest delete to d register 
nnoremap dd "ddd         "send latest delete to d register
nnoremap x "_x           "send char deletes to black hole, not worth saving
nnoremap <leader>p "dp   "paste what was deleted
nnoremap <leader>P "dP   "paste what was deleted

这种方法可以防止删除操作破坏yanks,但不会丧失对删除操作的注册——用户可以粘贴(回)删除的内容,而不是将其丢失在黑洞中(就像已接受的答案一样)。在上面的例子中,这种召回是通过两个前导p映射完成的。这种方法的一个好处是,它让您能够选择要粘贴的内容:(A)刚刚删除的内容,或(b)刚刚删除的内容。


寄存器0到9是最新的东西你拉或削减等,不包括删除的东西等。所以如果你拉/切一些东西,它也在寄存器0中,即使你说在那之后删除了东西,寄存器0仍然是你拉/切的最后一个东西。

yiw#转到默认寄存器和寄存器0

它猛拉光标所在的单词

删除的东西等将去默认寄存器,但不是寄存器0

标准模式:

“0p#放入寄存器0的内容

插入模式:

Ctrl-r 0 #放入寄存器0的内容

我也有一个朋友,他总是猛拉/切来注册x,哈哈。


下面的vscode设置应该允许dd和dw变成“_dd和”_dw,现在我们的remapper可以正常工作。

{
     "vim.normalModeKeyBindingsNonRecursive": [
        {
            "before": ["d"],
            "after": [ "\"", "_", "d" ]
        }
    ]
}

你可以创建一个简单的宏: q " _dwq

现在要在不覆盖寄存器的情况下删除下一个单词,可以使用@d


主要问题是在可视模式下使用p。下面的函数将恢复未命名寄存器的内容后,你粘贴的东西在视觉模式。

 function! MyPaste(ex)
  let save_reg = @"
  let reg = v:register
  let l:count = v:count1
  let save_map = maparg('_', 'v', 0, 1)
  exec 'vnoremap _ '.a:ex
  exec 'normal gv"'.reg.l:count.'_'
  call mapset('v', 0, save_map)
  let @" = save_reg
endfunction

vmap p :<c-u>call MyPaste('p')<cr>
vmap P :<c-u>call MyPaste('P')<cr>

用法和以前一样,register "的内容没有改变。


我发现从一开始就更容易插入'p'缓冲区。

复制(又名:yank)

# highlight text you want to copy, then:
"py

粘贴

# delete or highlight the text you want to replace, then:
"pp

优点(相对于删除到特定寄存器):

“pp很容易上手 不会在删除时意外覆盖粘贴缓冲区。


Noremap mm m

and

Noremap mx "_x

是我的处理方式。