Perl:提取与XML标记之间的模式匹配的子字符串

时间:2015-03-06 12:46:11

标签: regex xml perl

我需要在不使用模块的情况下解析XML文件。

在该XML文件中,我需要提取与模式匹配的2个标记(<mi> ... </mi>)之间的所有内容。

我有这个:

$xmlstring = my xml string
$pattern = "G2_CPU";
my $regex = "<mi>(.*?" . $pattern . ".*?)<\\/mi>";
my ($data) = $xmlstring =~ /$regex/i;

但是当我执行它时,在$data中,我在第一个<mi>标记和最后一个</mi>标记之间得到了所有内容。

我也尝试使用没有变量的正则表达式:/(<mi>.*?G2_CPU.*?<\/mi>)/,我得到了相同的结果。

我该怎么做?

2 个答案:

答案 0 :(得分:3)

假设这仍然是有效的XML,即<无法在标记打开和标记关闭之间显示, ,那些内容中没有CDATA标签,你可以使用:

my $re = qr{<mi>([^<]*? \Q$pattern\E [^<]*?)</mi>}ix;

也就是说,不要让任何字符到感兴趣的子字符串,只允许使用非标记的开头字符。

另外,我的第一直觉,如果我以为我会尝试go down the rabbit hole在没有合适的XML解析器的情况下解析XML,那么首先要在<mi>...</mi>之间提取文本,然后检查它是否存在包含我正在寻找的东西。

答案 1 :(得分:1)

你只需要在模式的开头添加一个贪婪的匹配,这样就可以捕获它的大部分:

my $regex = "(?:.*)<mi>(.*?" . $compteur . ".*?)<\/mi>";
             ^^^^^^

来自Shortest match issues

  

问题在于,即使使用非贪婪的匹配,Perl仍然存在   试图找到从最左边可能的点开始的匹配   字符串。

测试

档案p.pl

$xmlstring = "hello <mi>first mi</mi> and this is another <mi>second mi</mi> end." ;
$compteur="second";
my $regex = "(?:.*)<mi>(.*?" . $compteur . ".*?)<\/mi>";
my ($data) = $xmlstring =~ /$regex/i;
print "$data\n";

执行:

$ perl p.pl 
second mi