【问题标题】:Substitute the n-th occurrence of a word in vim替换 vim 中第 n 次出现的单词
【发布时间】:2011-03-05 16:05:19
【问题描述】:

我看到了其他关于查找第 n 次出现的单词/模式的问题,但我无法找到如何在 vim 中实际替换第 n 次出现的模式。有一种很明显的方法来硬编码所有出现的事件,比如

:s/.*\(word\).*\(word\).*\(word\).*/.*\1.*\2.*newWord.*/g 

有没有更好的方法来做到这一点?

【问题讨论】:

标签: regex vim sed substitution


【解决方案1】:

好吧,如果您这样做/gc,那么您可以计算它要求您确认的次数,并在您到达第 n 个时继续替换:D

【讨论】:

  • 是的,但我想在没有确认的情况下替换第 n 次出现(就像我必须编写脚本来做到这一点一样)。
【解决方案2】:

您可以通过使用多个搜索更简单地做到这一点。 :s/pattern/repl/ 命令中的空模式表示替换最近的搜索结果。

:/word//word//word/ s//newWord/
or
:/word//word/ s/word/newWord/

然后您可以通过执行@: 重复此操作多次,甚至可以通过10@: 重复该命令 10 次以上。

或者,如果我以交互方式执行此操作,我会执行以下操作:

3/word
:s//newWord/r

这将找到从光标开始的第三次出现的 word,然后执行替换。

【讨论】:

  • Hrm,这仍然存在许多问题,如果第一个单词是我们要查找的单词,'3/word' 将让我们出现第 4 次。另外,当我在找到第 n 个实例后尝试替换时,它仍然会替换第一个实例。
  • 3/word 将找到从光标开始的第三个匹配项。如果您想从那里开始,请使用gg 转到文件顶部。请注意,3/word 相当于输入 /word 三次,所以它肯定会找到第三次出现。
  • -1:如果所有单词都在同一行上(这就是我假设 OP 的意思),这些对我都不起作用。在这两个示例中,替换仍然发生在该行的第一个单词上。
【解决方案3】:

有关信息,

s/\%(\(pattern\).\{-}\)\{41}\zs\1/2/

也可以替换第 42 次出现。不过,我更喜欢the solution given by John Kugelman,它更简单——即使它不会将自身限制在当前行。

【讨论】:

  • @Luc Hermitte:您能告诉我答案中的“\%”是什么意思吗?看来是vim无法识别的操作符。
  • 类似于\(,但它告诉不要将括号匹配的内容绑定到\1。见:h /\%(,IIRC
【解决方案4】:

这回答了您的实际问题,但不是您的意图。

您询问替换第 n 次出现的单词(但似乎意思是“在一行内”)。这是所问问题的答案,以防有人像我一样找到它=)

对于奇怪的任务(例如需要将每 12 次出现的“狗”替换为“鹦鹉​​”),我喜欢使用递归记录。

先将@q中的录音空白

qqq

现在在 q 中开始新的录制

qq

接下来,手动做你想做的事(使用上面的例子,将第 12 次出现的“dog”替换为“parrot”):

/dog
nnnnnnnnnnn

删除“狗”并进入插入

diwi

键入鹦鹉

parrot

现在播放您当前空的“@q”录音

@q

什么都不做。

最后,停止录制:

q

现在你在@q 中的录音最后会调用自己。但是因为它按名称调用录音,所以它不再是空的了。所以,调用录音:

@q

它将重播录音,然后在最后,作为最后一步,再次重播自己。它将重复此操作直到文件结束。

TLDR;

qq
q
/dog
nnnnnnnnnnndiwiparrot<esc>
@q
q
@q

【讨论】:

    【解决方案5】:

    用 REPLACE 替换每行 Nth 个 PATTERN。

    :%s/\(\zsPATTERN.\{-}\)\{N}/REPLACE/
    

    【讨论】:

    • 请问zs和{N}是正则表达式的语法还是vim的语法?
    • 缩放锚点是 Vim 特定的 AFAIK(其他语言 IDK),请参阅 this great answer 关于 \zs 或在 Vim 中键入 :h \zs 以获取有关它的信息,{} 用于大多数语言,但具有不同的功能,主要用于匹配长度或模式或组匹配的出现次数(....){N},就像我在这里使用的那样。
    【解决方案6】:

    要替换 vim 中一行中第 n 次出现的 PATTERN,除了上面的答案之外,我只是想解释一下模式匹配,即它实际上是如何工作的,以便于理解。

    所以我将讨论\(.\{-}\zsPATTERN\)\{N} 解决方案,

    我将使用的示例是替换句子(字符串)中第二次出现的超过 1 个空格。 根据模式匹配码->

    1. 根据zs doc,

      \zs - 水平滚动文本以将光标定位在开头(左 侧)。

    2. .\{-}0 或更多尽可能少 (*)

      这里。匹配任何字符和 {} 的次数。 例如 ab{2,3}c 这里它将匹配 b 出现 2 次或 3 次的位置。

      在这种情况下,我们也可以使用.*,它是 0 或尽可能多的。 根据 vim non-greedy docs,“{-}”与“*”相同,但使用最短匹配优先算法。

    3. \{N} -> 匹配前一个原子的 n

      /\&lt;\d\{4}\&gt; 精确搜索 4 位数字,与 /\

      相同

      **忽略这​​些\&lt;\&gt;,它们用于精确搜索,例如搜索fred -> \&lt;fred\&gt; 将只搜索fred 而不是alfred。

    4. \( \) 组合整个模式。

    5. PATTERN 这里是您要匹配的模式 -> \s\{1,}(\s - 空格和 {1,} 如上所述,搜索 1 个或多个空格)

    "abc 子串定义"

        :%s/\(.\{-}\zs\s\{1,}\)\{2}/,/
    

    输出 -> "abc subtring,def"

    # explanation: first space would be between abc and substring and second 
    # occurence of the pattern would be between substring and def, hence that 
    # will be replaced by the "," as specified in replace command above. 
    

    【讨论】:

      猜你喜欢
      • 2014-11-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-09-08
      • 1970-01-01
      • 2017-03-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多