如何在 Vim 中快速更改变量名?

我使用 Vim 来阅读大量包含许多单个字母变量名的 C 和 Perl 代码。

当我在阅读代码的过程中,如果有一些命令可以将变量的名称更改为更有意义的名称,那就太好了,这样我就可以更快地阅读剩下的代码。

Is there some command in Vim which could let me do this quickly?

我不认为正则表达式有效,因为:

  1. 相同的单个字母名称在不同的范围块中可能有不同的用途; 以及

  2. 同样的字母组合可以是另一个更长的变量名、字符串文字或注释的一部分。

有什么已知的解决方案吗?

51170 次浏览

You could use the 'c' modifier in the global search and replace that would ask you for confirmation for each replace. It would take longer but it might work for a non-humongous code file:

%s/\$var/\$foo/gc

C 代表确认。

AFAIK,在 VIM 中没有实际的重构支持。当以重构为目的进行重命名时,我通常采取以下预防措施:

  1. 限制改变我使用标记的范围。
  2. 输入正则表达式时,用 < 和 > 括号括起名称。这将使其匹配整个单词,从而减少将发生的不正确重命名的类型。
  3. 不要进行多行替换以减少出现错误替换的可能性
  4. 仔细查看代码差异,如果它不是一个小的变化。

我最后的变化是这样的

:'a,'bs/\<foo\>/bar

如果没有一个用于 VIM 的重构工具,我很乐意犯错,但是我还没有看到它。

下面是如何重命名在当前范围 {}中定义的变量。

移动你的光标到变量的使用。按 gd。这意味着-移动光标到定义。 现在按 [{-这将带你到范围开始。 按 V-将打开视觉线选择。 按 %-将跳转到相反的 },从而将选择整个范围。 按 :s/-启动替代命令。 将插入匹配变量名的模式(按 gd之前的名称)。 /newname/gc<CR>-将启动搜索和替换与确认每场比赛。

现在您必须记录一个宏,或者更好地映射一个键。

以下是最终的映射:

" For local replace
nnoremap gr gd[{V%::s/<C-R>///gc<left><left><left>


" For global replace
nnoremap gR gD:%s/<C-R>///gc<left><left><left>

把这个放到你的 .vimrc或者直接执行。 按下本地变量上的 gr之后,您就可以进入 :s命令,您只需输入 new_variable_name并按下 Enter即可。

在 c 中,您可以使用 cscope 取得一些进展。它尝试理解语法,这样就有机会知道字母何时是变量。

如果这是跨多个文件的,您可以考虑查看 sed。使用 find 获取文件和 xargs 加 sed 以进行替换。假设您希望在所有匹配 * 的文件中将 a 替换为 a _ better _ name。C 你可以的

- name“ * . c”| xargs sed-i-e’s/a/a _ better _ name/g’

请记住,这将替换所有出现的 a,因此您可能需要一个更健壮的正则表达式。

把这个放进你的 Vimrc

" Function to rename the variable under the cursor
function! Rnvar()
let word_to_replace = expand("<cword>")
let replacement = input("new name: ")
execute '%s/\(\W\)' . word_to_replace . '\(\W\)/\1' . replacement . '\2/gc'
endfunction

:call Rnvar()调用它

expand("<cword>")获取光标下的单词。搜索字符串使用 %作为文件范围,而 \(\W\)模式在要替换的单词的边界处寻找非单词字符,并将它们保存在变量 \1\2中,以便重新插入到替换模式中。

我知道这是一个老问题,而@mykola-golubyev 的方式显然是 OP 问题中特定情况下的最佳答案(我假设这是一个模糊的代码,你可能会有多个块具有相同的变量名) ; 但问题的名称,这样的许多人来这里从谷歌搜索可能会寻找一个较少的情况特定的方式来重命名 VIM 中的变量——这些可以更简洁

I'm surprized no one suggested this way:

* :s// 新名字 /gc

*gn相同——它在光标下搜索单词的下一次出现,然后成为最后一个搜索模式,所以当您在替代命令中省略搜索模式时,VIM 假定这就是要搜索的模式。

对于少量的 var 拷贝,一个更快的方法是:

* cw 新名字 <esc>,然后在其他情况下重复 n.

搜索出现,cw换个词的命令,n到最后一个搜索词的下一个出现,.重复最后一个命令(即 将单词更改为 NEWNAME)

(我知道这一切的学分去 @ Doomedbunnie on Reddit)

另一个很酷的技巧是: (感谢@nobe4)

* cgn 新名字 <esc>,然后在其他情况下重复 .

cgn是“更改(查找下一个事件)的结果”。现在,这是 最后一道命令,您不需要 n去下一次发生,所以再次更少的中风,更重要的是,不需要交替 n.。但是,很明显,这个方法有一个缺点,那就是没有办法跳过一个事件。

以下是一些好处:

  • 没有地图,没有。Vimrc (或 init.VIM) ,这样你就可以在你遇到的任何 VIM 拷贝中使用它(例如在一些 VPS 或你朋友的机器上的一个快速任务,配置 VIM 你的方式会破坏“快速”的目的)
  • 使用 *gn进行单词选择非常快——只需按一下键(好吧,假设是1.5)
  • 使用 *gn可以确保不会在其他单词内得到任何匹配,就像 :%s/<C-R>//gc一样。击败手工输入 :%s/\<OLDNAME\>/NEWNAME/gc: 我个人往往忘记使用 \<的东西,以限制匹配整个单词只。
  • 不使用作用域只会导致跳过不需要的匹配的一些额外的 n笔画——可能比限制作用域所需的额外笔画还要少。在正常情况下,您的变量很可能在某种程度上本地化为某个代码块。