【问题标题】:vim range .+1,$ includes current line, affecting one line too muchvim range .+1,$ 包含当前行,对一行影响太大
【发布时间】:2021-01-16 03:18:42
【问题描述】:

我有一个 vim 脚本来帮助重构 Python 代码;根据文件,它会插入多个相等的 import 行,例如如果将许多行更改为使用getToolByName,则会出现多次from Products.CMFCore.utils import getToolByName

为了清理,我在脚本末尾附近有几行如下所示:

normal gg
/^\(from AccessControl import Unauthorized\>\)\?/
.+1,$s,^from AccessControl import Unauthorized\n,,e
normal gg
/^\(from Products.CMFCore.utils import getToolByName\>\)\?/
.+1,$s,^from Products.CMFCore.utils import getToolByName\n,,e

这个想法是:

  • 对于每个可能插入的导入行,
  • 转到文件顶部,
  • 查找包含此导入的第一行(好吧,从它开始,并且可能包含更多),
  • 并删除所有进一步行(.+1,$)与完全插入的导入匹配。

为了避免错误(这会伤害很多,尤其是通过:argdo 使用脚本时),我将搜索设为可选(\?),因为e 标志适用于仅限 :s 命令。如果该搜索未找到真正的匹配项,则以下 :.+1,$ s 命令也不应删除任何内容,因为它更具限制性。

(剩余插入的行需要手动移动)

但是,由于 \?,替换不仅删除了以下出现 (.+1),而且 所有 - 包括我想保留的第一个。

我该如何解决这个问题?

基于sed 的解决方案也会对我有所帮助。

版本: vim v7.4 (CentOS Linux) 和 gvim 8.1 在 Windows 上的问题相同。

谢谢!

编辑: 现在我有了一个解决方法,我仍然对不需要临时更改的“适当”解决方案感兴趣,因此如果一切正常,vim 会考虑文件未更改

【问题讨论】:

  • 考虑使用Vi and Vim StackExchange 来解决有关 Vim 的问题!

标签: vim sed


【解决方案1】:

这可能不是最好的解决方案,但这是我找到的解决方法:

在第一行normal gg 上方,我添加了代码以在文件末尾添加两行:

normal GoELEPHANT IN CAIRO
normal yyp

然后我将我的/.../ 行更改为无条件,但或者找到那些额外的行,例如:

normal gg
/^\(from AccessControl import Unauthorized\>\|ELEPHANT IN CAIRO\)/
.+1;$ s/^from AccessControl import Unauthorized\n//e

最后我删除了这些行:

g/^ELEPHANT IN CAIRO$/d

【讨论】:

    【解决方案2】:

    正如您所注意到的,出现问题是因为您搜索from AccessControl import Unauthorized 使用的是?,这实际上使其匹配每一行 行,而不是实际导入的第一行。

    您可以通过使用与您想要匹配的确切行匹配的模式来解决此问题,但使用:silent! 来防止任何错误破坏您的序列。

    这可行:

    normal gg
    silent! /^from AccessControl import Unauthorized\>/
    .+1,$s,^from AccessControl import Unauthorized\n,,e
    

    但更好的解决方案是使用一个范围,该范围可以找到模式并同时从下一行开始。您还可以使用:d 命令删除一行,使用:g//d 删除与特定正则表达式匹配的所有行(范围内)。此外,如果您两次使用相同的模式,那么在您的:g 命令上简单地使用// 将再次匹配相同的模式。

    把它们放在一起:

    :0/^from AccessControl import Unauthorized\>/+1,$g//d
    

    所以这从第 0 行开始(在文件开头之前,所以它也在文件的第一行匹配),然后找到第一次出现的模式,然后从下一行开始,看起来对于相同模式的所有其他匹配一直到文件末尾,并删除匹配的行。

    和之前一样,如果你不想在模式不匹配时看到错误(或者如果只有一个匹配,在这种情况下 :g// 将失败),你可以使用 :silent!再次压制它。

    :silent! 0/^from AccessControl import Unauthorized\>/+1,$g//d
    

    【讨论】:

    • 感谢您非常有帮助的回答! :silent! 部分是我在 / / ? 命令帮助中找不到的部分。我更改了我的脚本以使用你最后的单行。
    猜你喜欢
    • 2021-08-11
    • 1970-01-01
    • 1970-01-01
    • 2012-02-03
    • 2011-03-08
    • 2016-08-06
    • 2014-11-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多