Perl正则表达式匹配嵌入式标记一次

时间:2016-06-16 07:40:31

标签: regex perl

我有一些我希望根据标签匹配的文字只出现一次。 文本如下(一些随机字符可以包含除标签之外的任何内容):

<tag1><tag2><tag3>Some randome chars</tag3><tag3>Some randome chars</tag3><tag3>Some randome chars</tag3><tag3>Some randome chars</tag3></tag2></tag1>
<tag1><tag2><tag3>Some randome chars</tag3></tag2></tag1>
<tag1><tag2><tag3>Some randome chars</tag3><tag3>Some randome chars</tag3><tag3>Some randome chars</tag3></tag2></tag1>
<tag1><tag2><tag3>Some randome chars</tag3><tag3>Some randome chars</tag3></tag2></tag1>
<tag1><tag2><tag3>Some randome chars</tag3></tag2></tag1>
<tag1><tag2><tag3>Some randome chars</tag3><tag3>Some randome chars</tag3><tag3>Some randome chars</tag3><tag3>Some randome chars</tag3><tag3>Some randome chars</tag3><tag3>Some randome chars</tag3></tag2></tag1>
<tag1><tag2><tag3>Some randome chars</tag3><tag3>Some randome chars</tag3><tag3>Some randome chars</tag3><tag3>Some randome chars</tag3><tag3>Some randome chars</tag3></tag2></tag1>
<tag1><tag2><tag3>Some randome chars</tag3><tag3>Some randome chars</tag3><tag3>Some randome chars</tag3><tag3>Some randome chars</tag3></tag2></tag1>

我想要的匹配是:匹配tag2中只出现一次的tag3。

例如:

<tag2><tag3>something</tag3></tag2> is matched
<tag2><tag3>something</tag3><tag3>something</tag3></tag2> isn't matched

根据以上文字,预期输出为:第2行和第5行。

我试过的正则表达式(没有工作):

<tag2><tag3>(.*)?</tag3></tag2>
<tag2><tag3>(.*){1}</tag3></tag2>

3 个答案:

答案 0 :(得分:4)

我会敦促你不要使用正则表达式来操纵XML。正则表达式无法处理像XML这样的上下文语言,因此您构建了脆弱的代码 - 对XML格式(例如whitespacing)的完全有效的更改可能会中断。

所以相反:

#!/usr/bin/env perl
use strict;
use warnings;

use XML::Twig;

my $twig = XML::Twig->parse( \*DATA );

foreach my $element ( $twig->get_xpath('//tag2') ) {
   if ( scalar $element->children('tag3') == 1 ) {
      $element->print;
      print "\n";
   }
}

__DATA__
<root>
<tag1><tag2><tag3>Some randome chars</tag3><tag3>Some randome chars</tag3><tag3>Some randome chars</tag3><tag3>Some randome chars</tag3></tag2></tag1>
<tag1><tag2><tag3>Some randome chars</tag3></tag2></tag1>
<tag1><tag2><tag3>Some randome chars</tag3><tag3>Some randome chars</tag3><tag3>Some randome chars</tag3></tag2></tag1>
<tag1><tag2><tag3>Some randome chars</tag3><tag3>Some randome chars</tag3></tag2></tag1>
<tag1><tag2><tag3>Some randome chars</tag3></tag2></tag1>
<tag1><tag2><tag3>Some randome chars</tag3><tag3>Some randome chars</tag3><tag3>Some randome chars</tag3><tag3>Some randome chars</tag3><tag3>Some randome chars</tag3><tag3>Some randome chars</tag3></tag2></tag1>
<tag1><tag2><tag3>Some randome chars</tag3><tag3>Some randome chars</tag3><tag3>Some randome chars</tag3><tag3>Some randome chars</tag3><tag3>Some randome chars</tag3></tag2></tag1>
<tag1><tag2><tag3>Some randome chars</tag3><tag3>Some randome chars</tag3><tag3>Some randome chars</tag3><tag3>Some randome chars</tag3></tag2></tag1>
</root>

这将处理格式化的XML,但也只是在一行上。或者像这样:

<root>
  <tag1>
    <tag2>
      <tag3>Some randome chars</tag3>
      <tag3>Some randome chars</tag3>
      <tag3>Some randome chars</tag3>
      <tag3>Some randome chars</tag3>
    </tag2>
  </tag1>
  <tag1>
    <tag2>
      <tag3>Some randome chars</tag3>
    </tag2>
  </tag1>
  <tag1>
    <tag2>
      <tag3>Some randome chars</tag3>
      <tag3>Some randome chars</tag3>
      <tag3>Some randome chars</tag3>
    </tag2>
  </tag1>
  <tag1>
    <tag2>
      <tag3>Some randome chars</tag3>
      <tag3>Some randome chars</tag3>
    </tag2>
  </tag1>
  <tag1>
    <tag2>
      <tag3>Some randome chars</tag3>
    </tag2>
  </tag1>
  <tag1>
    <tag2>
      <tag3>Some randome chars</tag3>
      <tag3>Some randome chars</tag3>
      <tag3>Some randome chars</tag3>
      <tag3>Some randome chars</tag3>
      <tag3>Some randome chars</tag3>
      <tag3>Some randome chars</tag3>
    </tag2>
  </tag1>
  <tag1>
    <tag2>
      <tag3>Some randome chars</tag3>
      <tag3>Some randome chars</tag3>
      <tag3>Some randome chars</tag3>
      <tag3>Some randome chars</tag3>
      <tag3>Some randome chars</tag3>
    </tag2>
  </tag1>
  <tag1>
    <tag2>
      <tag3>Some randome chars</tag3>
      <tag3>Some randome chars</tag3>
      <tag3>Some randome chars</tag3>
      <tag3>Some randome chars</tag3>
    </tag2>
  </tag1>
</root>

或者像这样:

<root
><tag1
><tag2
><tag3
>Some randome chars</tag3><tag3
>Some randome chars</tag3><tag3
>Some randome chars</tag3><tag3
>Some randome chars</tag3></tag2></tag1><tag1
><tag2
><tag3
>Some randome chars</tag3></tag2></tag1><tag1
><tag2
><tag3
>Some randome chars</tag3><tag3
>Some randome chars</tag3><tag3
>Some randome chars</tag3></tag2></tag1><tag1
><tag2
><tag3
>Some randome chars</tag3><tag3
>Some randome chars</tag3></tag2></tag1><tag1
><tag2
><tag3
>Some randome chars</tag3></tag2></tag1><tag1
><tag2
><tag3
>Some randome chars</tag3><tag3
>Some randome chars</tag3><tag3
>Some randome chars</tag3><tag3
>Some randome chars</tag3><tag3
>Some randome chars</tag3><tag3
>Some randome chars</tag3></tag2></tag1><tag1
><tag2
><tag3
>Some randome chars</tag3><tag3
>Some randome chars</tag3><tag3
>Some randome chars</tag3><tag3
>Some randome chars</tag3><tag3
>Some randome chars</tag3></tag2></tag1><tag1
><tag2
><tag3
>Some randome chars</tag3><tag3
>Some randome chars</tag3><tag3
>Some randome chars</tag3><tag3
>Some randome chars</tag3></tag2></tag1></root>

在语义上与您的相同。

答案 1 :(得分:2)

你的正则表达式不起作用,因为你允许捕获组中的所有内容(.)。这非常贪婪,会尽可能地停留在最后</tag3>。如果您只想匹配不能包含标签的内容,则需要匹配除开始标记令牌之外的任何内容。

m{<tag2><tag3>([^<]+)</tag3></tag2>}g

regex101.com上试用。

答案 2 :(得分:1)

使用XML感知工具。我在xsh中尝试了以下内容,这是XML::LibXML

的包装器
ls //tag2[1=count(tag3)]

在为tag2添加行号后,我得到了

<tag2>2<tag3>Some randome chars</tag3></tag2>
<tag2>5<tag3>Some randome chars</tag3></tag2>