如何从a的最后一个匹配到b进行搜索和替换?

How to search and replace from the last match of a until b?

我有一个乳胶文件,我想在其中删除 \end{quoting} 之前的最后一个 \

我正在处理的文件部分与此类似:

\myverse{some text \
some more text \}%
%
\myverse{again some text \
this is my last line \}%
\footnote{possibly some footnotes here}%
%
\end{quoting}

超过数百行,可能涵盖 50 个 quoting 环境。

我试过 :%s/\\}%\(\_.\{-}\)\end{quoting}/}%\end{quoting}/gc 但不幸的是 non-greedy 量词 \{-} 仍然太贪心了。 它从我的示例的第二行开始捕获,直到引用环境结束,我猜贪心量词会赶上文件中的最后一个 \end{quoting}。有没有可能通过搜索和替换来做到这一点,或者我应该为此编写一个宏吗?

编辑:我的预期输出看起来像这样:

this is my last line }%
\footnote{possibly some footnotes here}%
%
\end{quoting}

(我应该补充一点,我现在已经通过编写一个小宏解决了这个任务,但我仍然很好奇它是否也可以通过搜索和替换来完成。)

你在使用非贪婪 multi 的正确轨道上。 Vim 帮助文件 说明,

"{-}" is the same as "*" but uses the shortest match first algorithm.

但是,下一行会警告您遇到的问题。

BUT: A match that starts earlier is preferred over a shorter match: "a{-}b" matches "aaab" in "xaaab".

据我所知,最好的解决方案是使用宏。

认为 您正在尝试从 end{quoting} 之前的 最后一次 匹配 \}% , 直到 end{quoting}, 在这种情况下你真的不想要 any 字符 (\_.), 你想要 "any character that isn't \}%" (是的我知道这不是一个单一的字符,但基本上就是这样。

所以,只需(哈!)更改您的模式以使用 \%(\%(\\}%\)\@!\_.\)\{-} 而不是 \_.\{-};这意味着该模式不能包含多个 \}% 序列,从而实现您的目标(据我所知)。

这使用负零宽度先行模式\@!来确保下一个匹配任何字符, 仅限于不匹配我们想要避免的特定文本(但除此之外,任何 else 仍然匹配)。有关更多信息,请参阅 :help /zero-width。

即您的最终命令是:

:%s/\\}%\(\%(\%(\\}%\)\@!\_.\)\{-}\)\end{quoting}/}%\end{quoting}/g

(我注意到您的 "expected" 输出出于某种原因不包含前几行,它们只是被省略了还是命令应该删除它们?)