使用正则表达式在块列表中获取一个文本块

时间:2009-11-25 14:26:05

标签: regex

Edit2:请使用正则表达式匹配解决方案。谢谢!

编辑:我正在寻找正则表达式解决方案,如果它存在的话。我有其他块具有相同的非XML数据,我不能使用Perl,我添加了Perl标签,因为我更熟悉Perl中的正则表达式。提前谢谢!

我的列表如下:

<Param name="Application #" value="1">
  <Param name="app_id" value="32767" /> 
  <Param name="app_name" value="App01" /> 
  <Param name="app_version" value="1.0.0" /> 
  <Param name="app_priority" value="1" /> 
</Param>
<Param name="Application #" value="2">
  <Param name="app_id" value="3221" /> 
  <Param name="app_name" value="App02" /> 
  <Param name="app_version" value="1.0.0" /> 
  <Param name="app_priority" value="5" /> 
</Param>
<Param name="Application #" value="3">
  <Param name="app_id" value="32" /> 
  <Param name="app_name" value="App03" /> 
  <Param name="app_version" value="1.0.0" /> 
  <Param name="app_priority" value="2" /> 
</Param>

如果我只知道app_name的值,如何为一个应用程序获取一个块。例如对于App02我想要

<Param name="Application #" value="2">
  <Param name="app_id" value="3221" /> 
  <Param name="app_name" value="App02" /> 
  <Param name="app_version" value="1.0.0" /> 
  <Param name="app_priority" value="5" /> 
</Param>

是否可以获取它,如果其他“name =”行未知(但总是name="app_name"Param name="Application #")?

可以在单个正则表达式匹配中完成吗? (不一定是,但感觉可能有办法)。

6 个答案:

答案 0 :(得分:4)

因为您的内容似乎是某些XML,为什么不使用真正的解析器来完成任务呢?

use XML::XPath;
use XML::XPath::XMLParser;

my $xp = XML::XPath->new(filename => 'test.xhtml');

my $nodeset = $xp->find('/Param[@name=\'Application #\']'); # find all applications

foreach my $node ($nodeset->get_nodelist) {
    print "FOUND\n\n", 
        XML::XPath::XMLParser::as_string($node),
        "\n\n";
}

您可以在此处详细了解XPath,并在w3c处获得完整参考。

我建议你使用reg exp来执行该任务,因为它会变得复杂而且无法维护。

note :也可以使用DOM API取决于您最喜欢的那个。

答案 1 :(得分:3)

这似乎是bogus XML的悲惨案例。错误地尝试创造enterprisey software充其量。开发人员可以使用合理的配置文件格式,例如:

[App03]
app_id = 32767
app_version = 1.0.0
...

但他们决定用无意义的BSXML驱使每个人疯狂。

我想说,如果此文件的大小小于10 MB,请继续使用XML::Simple。如果文件确实只包含 完全 的重复块,则可以使用以下解决方案:

#!/usr/bin/perl

use strict; use warnings;

my %apps;

{
    local $/ = "</Param>\n";
    while ( my $block = <DATA> ) {
        last unless $block =~ /\S/;
        my %appinfo = ($block =~ /name="([^"]+?)"\s+value="([^"]+?)"/g);
        $apps{ $appinfo{app_name} } = \%appinfo;
    }
}

use Data::Dumper;
print Dumper $apps{App03};

编辑:如果你不能使用Perl并且你不会告诉我们你可以使用什么,那么我无能为力但是指出

/name="([^"]+?)"\s+value="([^"]+?)"/g

会为您提供所有name - value对。

答案 2 :(得分:1)

似乎使用XML阅读器库更合适,但我不知道Perl足以建议一个。

答案 3 :(得分:1)

Perl的XML DOM Parser可能适用于此。

答案 4 :(得分:1)

我也更喜欢解析器解决方案。如果你绝对 使用正则表达式并理解这种方法的所有缺点,那么以下正则表达式应该可以工作:

<Param name="Application #"[^>]*>\s+<Param[^>]*>\s+<Param name="app_name" value="App02" />\s+(?:<Param[^>]*>\s+){2}</Param>

这在很大程度上依赖于示例中的结构。标签的重新排序,附加标签的引入或标签的(颤抖)嵌套将破坏正则表达式。

答案 5 :(得分:1)

我建议使用XML解析器之一,但如果你不能这样做,那么下面的快速和脏代码应该这样做:

my ($rez) = $data =~/\<Param\s+name\s*=\s*"Application\s#"\s+value\s*=\s*"2"\>((?:.|\n)*?)^\<\/Param\>/m;
print $rez;

(假设$ data包含您的xml作为单个字符串,可能是多行)