如何在 Vim 中的单个命令调用中从光标位置开始并环绕文件末尾进行全局搜索和替换?
当我使用 /
Normal-mode 命令进行搜索时:
/\vSEARCHTERM
Vim 从光标位置开始搜索并继续向下,环绕到顶部。但是,当我使用 :substitute
命令搜索和替换时:
:%s/\vBEFORE/AFTER/gc
Vim 相反从文件顶部开始。
有没有办法让Vim从光标位置开始执行搜索和替换,并在到达末尾后绕到顶部?
When I search with the /
Normal-mode command:
/\vSEARCHTERM
Vim starts the search from the cursor position and continues downwards, wrapping around to the top. However, when I search and replace using the :substitute
command:
:%s/\vBEFORE/AFTER/gc
Vim starts at the top of the file, instead.
Is there a way to make Vim perform search and replace starting from the cursor position and wrapping around to the top once it reaches the end?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
您已经在使用范围
%
,它是1,$
的简写,表示整个文件。要从当前行转到末尾,请使用.,$
。句点表示当前行,$
表示最后一行。因此命令将是:但是可以假定
.
或当前行,因此可以删除:有关更多帮助,请参阅
You are already using a range,
%
, which is short hand for1,$
meaning the entire file. To go from the current line to the end you use.,$
. The period means current line and$
means the last line. So the command would be:But the
.
or current line can be assumed therefore can be removed:For more help see
1. 使用以下方法实现相关行为并不难
两步替换:
首先,对从以下位置开始的每一行运行替换命令
当前命令直到文件末尾:
然后,使用相同的搜索重复
:substitute
命令模式、替换字符串和标志,使用
:&
命令(参见
:help :&
):然而,后者在行范围内执行替换
从文件的第一行到上一个上下文所在的行
标记已设置,减一。从第一个
:substitute
命令开始在开始实际替换之前存储光标位置,
''
寻址的行是之前的当前行该替换命令已运行。 (
''
地址指的是'
伪标记;有关详细信息,请参阅:help :range
和:help ''
。)请注意第二个命令(在
|
命令分隔符之后 - 请参阅:help :bar
) 当模式或标志时不需要任何更改在第一个中被更改。
2. 为了节省一些打字,以便调出框架
上面的命令行替换命令,可以定义
正常模式映射,如下所示:
尾随
部分是必需的将光标移动到命令行的开头 (
) 并然后向右四个字符 (
× 4),因此将其放在前两个斜线符号之间,为用户做好准备
开始输入搜索模式。一旦获得所需的图案和
替换已准备就绪,可以通过按运行生成的命令
输入。
(人们可能会考虑在上面的映射中使用
//
而不是///
,如果您喜欢先键入模式,然后键入分隔斜杠
oneself,后跟替换字符串,而不是使用
向右箭头将光标移动到已存在的分隔符上
替换部分开始的斜杠。)
1. It is not hard to achieve the behavior in question using
a two-step substitution:
First, the substitution command is run for each line starting from
the current one until the end of file:
Then, that
:substitute
command is repeated with the same searchpattern, replacement string, and flags, using the
:&
command(see
:help :&
):The latter, however, performs the substitution on the range of lines
from the first line of the file to the line where the previous context
mark has been set, minus one. Since the first
:substitute
commandstores the cursor position before starting actual replacements, the
line addressed by
''
is the line that was the current one beforethat substitution command was run. (The
''
address refers to the'
pseudo-mark; see:help :range
and:help ''
for details.)Note that the second command (after the
|
command separator—see:help :bar
) does not require any change when the pattern or flagsare altered in the first one.
2. To save some typing, in order to bring up the skeleton of
the above substitution command in the command line, one can define
a Normal-mode mapping, like so:
The trailing
<c-b><right><right><right><right>
part is necessaryto move the cursor to the beginning of the command line (
<c-b>
) andthen four characters to the right (
<right>
× 4),thus putting it between the first two slash signs, ready for the user
to start typing the search pattern. Once the desired pattern and the
replacement are ready, the resulting command can be run by pressing
Enter.
(One might consider having
//
instead of///
in the mapping above,if one prefers to type the pattern and then type the separating slash
oneself, followed by the replacement string, instead of using the
right arrow to move the cursor over an already present separating
slash starting the replacement part.)
%
是1,$
的快捷方式
( Vim help =>
:help :%
等于 1,$ (整个文件)。).
是光标位置,所以你可以从头开始替换文档直到光标
等
我强烈建议您阅读有关范围
:help range
的手册,因为几乎所有命令都适用于范围。%
is a shortcut for1,$
( Vim help =>
:help :%
equal to 1,$ (the entire file).).
is the cursor postion so you can doTo replace from the beginning of the document till the cursor
etc
I strongly suggest you read the manual about range
:help range
as pretty much all commands work with a range.我终于想出了一个解决方案,解决了这样一个事实:退出搜索会回到文件的开头,而无需编写一个巨大的函数……
你不会相信我花了多长时间才想出这个。只需添加一个是否换行的提示:如果用户再次按
q
,则不换行。所以基本上,通过点击qq
而不是q
来退出搜索! (如果你确实想换行,只需输入y
。)我实际上已将其映射到热键。因此,例如,如果您想从当前位置开始搜索并替换光标下的每个单词,则使用
q*
:I've FINALLY come up with a solution to the fact that quitting the search wraps around to the beginning of the file without writing an enormous function...
You wouldn't believe how long it took me to come up with this. Simply add a prompt whether to wrap: if the user presses
q
again, don't wrap. So basically, quit search by tappingqq
instead ofq
! (And if you do want to wrap, just typey
.)I actually have this mapped to a hotkey. So, for example, if you want to search and replace every word under the cursor, starting from the current position, with
q*
:这里有一些非常粗略的内容,解决了使用两步方法(
:,$ s/BEFORE/AFTER/gc|1,''-&&
) 或带有中间 “从文件开头继续?”提示方法:此函数使用一些技巧来检查我们是否应该绕回顶部:
Here’s something very rough that addresses the concerns about wrapping the search around with the two-step approach (
:,$s/BEFORE/AFTER/gc|1,''-&&
) or with an intermediate “Continue at beginning of file?”-prompt approach:This function uses a couple of hacks to check whether we should wrap around to the top:
s
register and inspecting last character of it.s
register.我参加聚会迟到了,但我经常依赖迟到的 stackoverflow 回答者来不这样做。我收集了有关 reddit 和 stackoverflow 的提示,最好的选择是在搜索中使用
\%>...c
模式,该模式仅在光标之后匹配。也就是说,它也会打乱下一个替换步骤的模式,并且很难输入。为了抵消这些影响,自定义函数必须随后过滤搜索模式,从而将其重置。见下文。
我一直在用一个映射代替下一个事件并跳转到下一个事件,而不是更多(无论如何这是我的目标)。我确信,在此基础上,可以制定出全球替代方案。请记住,在开发针对
:%s/.../.../g
之类的解决方案时,下面的模式会过滤掉剩余所有行中的匹配项到光标位置——但在单次替换完成后被清除,因此它会立即失去该效果,跳转到下一个匹配,从而能够逐个运行所有匹配。I am late to the party, but I relied too often on such late stackoverflow answerrs to not do it. I gathered hints on reddit and stackoverflow, and the best option is to use the
\%>...c
pattern in the search, which matches only after your cursor.That said, it also messes up the pattern for the next replacement step, and is hard to type. To counter those effects, a custom function must filter the search pattern afterwards, thus resetting it. See below.
I have contended myself with a mapping that replaces the next occurence and jumps to the following after, and not more (was my goal anyway). I am sure, building on this, a global substitution can be worked out. Keep in mind when working on a solution aiming at something like
:%s/.../.../g
that the pattern below filters out matches in all lines left to the cursor position — but is cleaned up after the single substitution completes, so it loses that effect directly after, jumps to the next match and thus is able to run through all matches one by one.