Perl正则表达式匹配:关键字可能存在也可能不存在

时间:2017-03-14 03:01:07

标签: regex perl

我有以下字符串输入:

<Name>IncludeLeafPortfolios</Name><DataType>Boolean</DataType><Value>True</Value>
<Name>HierarchyDate</Name><DataType>Int</DataType><IsFixed>false</IsFixed>
<Name>HierarchyDate</Name><DataType>Int</DataType>
<Name>HierarchyDate</Name><DataType>Int</DataType><Value>0</Value><IsFixed>false</IsFixed>
<Name>HierarchyDate</Name><DataType>Int</DataType><Value>0</Value><IsFixed>false</IsFixed>

名称标签始终存在且很有意义。 DataType不感兴趣。 值标记和IsFixed标记可能存在也可能不存在。目标是捕获Value标记,IsFixed标记,如果其中一个存在或两者都存在。

我的解决方案无效:

$element =~ m/^<Name>([\w\s]*)<\/Name>.*([<Value>[\w+\d+]<\/Value>]?)(<IsFixed>[\w+]<\/IsFixed>])?$

请建议。感谢。

2 个答案:

答案 0 :(得分:1)

该数据看起来像XML。使用类似XML::LibXML的库解析它,然后对生成的结构执行操作。

不要使用正则表达式来处理XML。 The results are just as bad as trying to use regular expressions for HTML.

答案 1 :(得分:0)

XML是上下文敏感的。正则表达式不是。由于这个原因,您无法使用正则表达式可靠地解析XML。

所以使用解析器。我喜欢XML::Twig,它会有点像这样:

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

use XML::Twig;
use Data::Dumper;

my $twig = XML::Twig -> new -> parsefile ( 'your_file.xml' );

my @keys = qw ( Name Value IsFixed ); 

my @rows; 
my %current_row; 
#iterate children
foreach my $node ( $twig -> root -> children ) { 
   #extract tag and content
   my $tag = $node -> tag;
   my $content = $node -> text; 
   $current_row{$tag} = $content; 
   #if it's a name tag, assume it's a new row. 
   if ($tag eq 'Name' and %current_row) {
       push @rows, {%current_row};
       undef %current_row;
   }
}
#output results. 
print join ",", @keys, "\n";
foreach my $row ( @rows ) {
   print join ",", (map { $row -> {$_} // '' } @keys),"\n";
}

哪个输出:

Name,Value,IsFixed,
IncludeLeafPortfolios,,,
HierarchyDate,True,,
HierarchyDate,,false,
HierarchyDate,,,
HierarchyDate,0,false,
但是,我会注意到你的XML很乱 - 你确定它是如何构建的吗?因为通常,如果您已经关联了&#39;标签,然后他们在一个节点内分组。

e.g。类似的东西:

<xml>
  <item>
     <Name>HierarchyDate</Name><DataType>Int</DataType><IsFixed>false</IsFixed>
  </item>
</xml>

这会大大简化问题,因为你可以:

foreach my $item ( $twig -> root -> children ) {
   print join ",", (map { $item -> first_child_text($_) // '' } @keys),"\n"; 
}