当我用
搜索时/\vSEARCHTERM
Vim从光标位置向下开始搜索,它将环绕到顶部。但是当搜索&替换使用
:%s/\vBEFORE/AFTER/gc
Vim从文件的顶部开始。
有没有办法让Vim搜索&从光标位置开始替换并在到达结尾时回绕到顶部?
答案 0 :(得分:152)
您已使用范围%
,这是1,$
的简写,意味着整个文件。要从当前行转到结尾,请使用.,$
。句点表示当前行,$
表示最后一行。所以命令是:
:.,$s/\vBEFORE/AFTER/gc
但可以假设.
或当前行可以删除:
:,$s/\vBEFORE/AFTER/gc
如需更多帮助,请参阅
:h range
答案 1 :(得分:45)
%
是1,$
的快捷方式
(Vim help => :help :%
等于1,$(整个文件)。)
.
是光标位置,因此您可以
:.,$s/\vBEFORE/AFTER/gc
从文档的开头替换到光标
:1,.s/\vBEFORE/AFTER/gc
等
我强烈建议您阅读有关范围:help range
的手册,因为几乎所有命令都适用于范围。
答案 2 :(得分:45)
使用两步替换来实现行为并不困难:
:,$s/BEFORE/AFTER/gc|1,''-&&
首先,从每个行开始执行替换命令
当前的一个直到文件结束。然后,:substitute
命令是
用相同的搜索模式,替换字符串和标志重复,
使用:&
命令。然而,后者执行替换
在从文件的第一行到行的行的范围
已设置上一个上下文标记,减去一个。自从第一次
:substitute
命令在开始实际之前存储光标位置
替换,由''
解决的行是该行
在该替换命令运行之前的当前一个。
请注意,第二个命令(在|
符号之后)不需要任何命令
当第一个的模式或标志被改变时改变。
答案 3 :(得分:3)
我终于提出了一个解决方案,即在不编写巨大功能的情况下退出搜索包裹到文件的开头...
你不会相信我花了多长时间来提出这个问题。只需添加是否换行的提示:如果用户再次按下q
,则不要换行。所以基本上,通过点击qq
而不是q
退出搜索! (如果你想要换行,只需输入y
。)
:,$s/BEFORE/AFTER/gce|echo 'Continue at beginning of file? (y/q)'|if getchar()!=113|1,''-&&|en
我实际上已将其映射到热键。因此,例如,如果您想要搜索并替换光标下的每个单词,从当前位置开始,使用q*
:
exe 'nno q* :,$s/\<<c-r>=expand("<cword>")<cr>\>//gce\|echo "Continue at beginning of file? (y/q)"\|if getchar()==121\|1,''''-&&\|en'.repeat('<left>',77)
答案 4 :(得分:1)
这里有一些非常粗略的内容,解决了使用the two-step approach(:,$s/BEFORE/AFTER/gc|1,''-&&
)或中间"Continue at beginning of file?"方法解决搜索问题的问题:
" Define a mapping that calls a command.
nnoremap <Leader>e :Substitute/\v<<C-R>=expand('<cword>')<CR>>//<Left>
" And that command calls a script-local function.
command! -nargs=1 Substitute call s:Substitute(<q-args>)
function! s:Substitute(patterns)
if getregtype('s') != ''
let l:register=getreg('s')
endif
normal! qs
redir => l:replacements
try
execute ',$s' . a:patterns . 'gce#'
catch /^Vim:Interrupt$/
return
finally
normal! q
let l:transcript=getreg('s')
if exists('l:register')
call setreg('s', l:register)
endif
endtry
redir END
if len(l:replacements) > 0
" At least one instance of pattern was found.
let l:last=strpart(l:transcript, len(l:transcript) - 1)
" Note: type the literal <Esc> (^[) here with <C-v><Esc>:
if l:last ==# 'l' || l:last ==# 'q' || l:last ==# '^['
" User bailed.
return
endif
endif
" Loop around to top of file and continue.
" Avoid unwanted "Backwards range given, OK to swap (y/n)?" messages.
if line("''") > 1
1,''-&&"
endif
endfunction
这个函数使用了几个hack来检查我们是否应该回到顶部:
答案 5 :(得分:1)
我参加聚会的时间很晚,但是我太过依赖如此晚的stackoverflow应答程序而没有这样做。我收集了有关reddit和stackoverflow的提示,最好的选择是在搜索中使用\%>...c
模式,该模式仅在光标之后匹配。
也就是说,它还会弄乱下一个替换步骤的模式,并且很难键入。为了应对这些影响,自定义函数必须随后过滤搜索模式,从而将其重置。见下文。
我已经为自己争辩了一个映射,该映射替换了下一次出现的内容,之后又跳到下一个出现的内容,并且没有更多(无论如何是我的目标)。我相信,在此基础上,可以制定出全球替代方案。在针对:%s/.../.../g
之类的解决方案进行工作时,请牢记以下模式会过滤掉光标位置左侧的 all 行中的匹配项-但在单次替换完成后会被清除,因此它会立即失去该效果,跳至下一场比赛,因此能够一次一站地进行所有比赛。
fun! g:CleanColFromPattern(prevPattern)
return substitute(a:prevPattern, '\V\^\\%>\[0-9]\+c', '', '')
endf
nmap <F3>n m`:s/\%><C-r>=col(".")-1<CR>c<C-.r>=g:CleanColFromPattern(getreg("/"))<CR>/~/&<CR>:call setreg("/", g:CleanColFromPattern(getreg("/")))<CR>``n