0

我需要在<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>
4

2 回答 2

4

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

图案:

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

让我们分解一下...

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

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

组 1 之后是\@<=。这是一个零宽度的正向回顾。它防止开始标签包含在匹配的文本中(例如,对于 s///)。

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

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

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

于 2009-04-10T02:42:13.610 回答
3

必须在vim中完成吗?你可以作弊,并打开第二个窗口,在其中将某些内容输入更多/更少,告诉你要在 vim 中转到哪个行号?

- 编辑 -

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

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

将显示“标签”(或其他更长的匹配名称)的元素/块,带有行号,更少,然后您可以在每个块中搜索其他文本。

足够近?

- 编辑 -

在“少”内,输入

/MATCH

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

在 vi[m] 内,输入

:n

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

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

于 2009-04-10T01:13:33.683 回答