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

时间:2009-04-10 00:41:28

标签: vim design-patterns match

我需要在<Annotation></Annotation>之间获取所有文字,其中出现单词MATCH。我怎么能在VIM中做到这一点?

<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>

2 个答案:

答案 0 :(得分:4)

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

模式:

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

让我们分解......

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

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

第1组之后是\@<=。这是一个零宽度的正面观察。它可以防止start-tag包含在匹配的文本中(例如,对于s ///).

第3组是\(<\/Annotation\)\@!\_.。它包括Group 4,它匹配Attribute end-tag的开头。 \@!是零宽度否定前瞻,\_.匹配任何字符(包括换行符)。这些组一起匹配除属性结束标记开始之外的任何字符。第3组之后是非贪婪的重复标记\{-},以便它匹配MATCH之前的最小文本块。如果您使用\_.而不是Group 3,匹配的文本可能包含包含MATCH的Annotation元素的结束标记,并继续使用MATCH进入下一个Annotation元素。 (试试吧。)

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

第5组很简单:它是结束标记。 \@=是零宽度正向前瞻,其中包含的原因与起始标记的\@<=相同。我们必须重复<\/Attribute而不是使用\4,因为未捕获具有零宽度修饰符的组。

答案 1 :(得分:3)

是否必须在vim中完成?你可以作弊,并打开第二个窗口,你可以用更多/更少的东西来管理你在vim中要去的行号吗?

- 编辑 -

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

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

将显示“tag”(或其他较长匹配名称)的元素/块,其中包含行号,然后您可以在每个块中搜索其他文本。

足够近?

- 编辑 -

在“less”内,输入

/MATCH

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

在vi [m]内,输入

:n

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

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