如何在 VIM 中从 A 到 B 重复匹配?

How can I repeatedly match from A until B in VIM?

提问人:Léo Léopold Hertz 준영 提问时间:4/10/2009 最后编辑:EddieLéo Léopold Hertz 준영 更新时间:4/11/2009 访问量:617

问:

我需要获取 和 之间的所有文本,其中出现单词。如何在 VIM 中做到这一点?<Annotation></Annotation>MATCH

<Annotation about="MATCH UNTIL </Annotation>   " timestamp="0x000463e92263dd4a" href="     5raS5maS90ZWh0YXZha29rb2VsbWEvbGFza2FyaS8QyrqPk5L9mAI">                                                                        
  <Label name="las" />
  <Label name="_cse_6sbbohxmd_c" />
  <AdditionalData attribute="original_url" value="MATCH UNTIL </Annotation>       " />
</Annotation>
<Annotation about="NO MATCH" href="     Cjl3aWtpLmhlbHNpbmtpLmZpL2Rpc3BsYXkvbWF0aHN0YXRLdXJzc2l0L0thaWtraStrdXJzc2l0LyoQh_HGoJH9mAI">
  <Label name="_cse_6sbbohxmd_c" />
  <Label name="courses" />
  <Label name="kurssit" />
  <AdditionalData attribute="original_url" value="NO MATCH" />
</Annotation>
<Annotation about="MATCH UNTIL </ANNOTATION>     " score="1" timestamp="0x000463e90f8eed5c" href="CiZtYXRoc3RhdC5oZWx     zaW5raS5maS90ZWh0YXZha29rb2VsbWEvKhDc2rv8kP2YAg">
  <Label name="_cse_6sbbohxmd_c" />
  <Label name="exercises_without_solutions" />
  <Label name="tehtäväkokoelma" />
  <AdditionalData attribute="original_url" value="MATCH UNTIL </ANNOTATION>" />
</Annotation>
vim 设计模式 匹配

评论

0赞 Eddie 4/10/2009
我假设您想以理解 XML 的方式执行此操作,因此不是元素结尾的 </ANNOTATION> 的出现不会被 VIM 匹配,而是被计为匹配体的一部分?如果是这样,我不知道 VIM 是否可以像这样进行 XML 感知 patttern 匹配。
0赞 Eddie 4/10/2009
此外,我还尝试使示例的格式更易于查看。我假设属性中的空格是有目的的,并将其留在那里。
0赞 Joe Holloway 4/10/2009
“获取所有文本”是什么意思?突出显示它?拉扯它?将其附加到命名缓冲区?
0赞 Léo Léopold Hertz 준영 4/10/2009
jholloway7:我不知道如何将其附加到命名缓冲区并将突出显示的文本保存到单独的文件中。
0赞 Gumbo 4/11/2009
您的 XML 无效。属性值中不允许使用。<

答:

3赞 Roboprog 4/10/2009 #1

必须在 vim 中完成吗?你能作弊吗,打开第二个窗口,在其中你通过管道将一些东西输送到或多或少中,告诉你在 vim 中要转到哪个行号?

--编辑--

我从未在 vi[m] 中进行过多行匹配/搜索。但是,要在另一个窗口中作弊:

perl -n -e 'if ( /<tag/ .. /<\/tag/)' -e '{ print "$.:$_"; }' file.xml | less

将显示“标签”(或其他较长匹配的名称)的元素/块,以及行号,以 less 为单位,然后您可以在每个块中搜索其他文本。

够近吗?

--编辑--

在“less”中,键入

/MATCH

以搜索 MATCH 的出现次数。左边距将是该实例(在目标元素/标签内)所在的行号。

在 vi[m] 中,键入

:n

其中“n”是所需的行号。

当然,如果你真正想做的是某种搜索/拉扯/替换,那就更复杂了。在这一点上,awk / perl / ruby(或类似的东西,符合你的口味......还是 xsl?确实是您应该用于转换的工具。

评论

0赞 Eddie 4/10/2009
我认为这样的东西将是唯一可能的答案,因为要做到这一点,您需要使用XML解析器。
0赞 Léo Léopold Hertz 준영 4/10/2009
MATCH这个词应该在哪里?代替..?
4赞 Nathan Kitchen 4/10/2009 #2

首先,免责声明:任何使用正则表达式对 XML 进行切片和切块的尝试都是脆弱的;一个真正的XML解析器会做得更好。

模式:

\(<Annotation\(\s*\w\+="[^"]\{-}"\s\{-}\)*>\)\@<=\(\(<\/Annotation\)\@!\_.\)\{-}"MATCH\_.\{-}\(<\/Annotation>\)\@=

让我们分解一下......

第 1 组是 。它与 Attribute 元素的 start-tag 匹配。组 2 嵌入在组 1 中,与属性匹配,可以重复 0 次或多次。<Annotation\(\s*\w\+="[^"]\{-}"\s\{-}\)*>

第 2 组是 。这些作品中的大多数是常用的;最不寻常的是 ,这意味着非贪婪的重复(在兼容 Perl 的正则表达式中)。最后的非贪婪空格匹配对性能很重要;如果没有它,Vim 将尝试各种可能的方法在组 2 的末尾和组 2 的下一个出现的开头之间的属性之间拆分空格。\s*\w\+="[^"]\{-}"\s\{-}\{-}*?\s*\s*

第 1 组后跟 。这是一个零宽度的正向后视。它可以防止将开始标记包含在匹配的文本中(例如,对于 s///)。\@<=

第 3 组是 。它包括组 4,它与 Attribute end-tag 的开头匹配。是零宽度的负前瞻,与任何字符(包括换行符)匹配。总之,这对任何字符进行分组,但属性结束标记开始的地方除外。第 3 组后面跟着一个非贪婪的重复标记,以便它与 MATCH 之前的最小文本块匹配。如果要使用组 3 代替,则匹配的文本可以包含包含 MATCH 的 Annotation 元素的结束标记,并继续到 MATCH 的下一个 Annotation 元素。(试试吧。\(<\/Annotation\)\@!\_.\@!\_.\{-}\_.

接下来的一点很简单:在结束标记之前找到 MATCH 和最少数量的其他字符。

第 5 组很简单:它是结束标签。 是一个零宽度的正前瞻,此处包含它的原因与 for the start-tag 相同。我们必须重复而不是使用,因为不会捕获具有零宽度修饰符的组。\@=\@<=<\/Attribute\4