我一直试着让这个工作但没有运气。这是我的文本文件(first.txt)
<metric>
<baseFilter>
<and>
<or>
<value field="id">1111</value>
<value field="id">2222</value>
</or>
<or>
<value field="resolution" />
</or>
</metric>
我想用第二个文本文件(second.txt)替换第一个“或”和“/或”之间的字符串。我可以在第一个“或”和“/或”之间有50个或更多的值字段行,因此,我在“或”和“/或”之间搜索字符串,并用second.txt中的任何内容替换。
<value field="id">3333</value>
<value field="id">4444</value>
<metric>
<baseFilter>
<and>
<or>
<value field="id">3333</value>
<value field="id">4444</value>
</or>
<or>
<value field="resolution" />
</or>
</metric>
我已经获得了以下perl代码。
#!/usr/bin/perl
my $first = 'first.txt';
open (my $fh, '<', $first) or die "cannot open file $first";
{
local $/;
$first = <$fh>;
}
$find = "([\s]+)(<or>)([\n\r\s]+).*(\n|.)+?([\n\r\s]+)(<\/or>)";
my $content = 'second.txt';
open (my $fh, '<', $content) or die "cannot open file $content";
{
local $/;
$content = <$fh>;
}
$first =~ s/$find/$1$2$3$content$5$6/;
print "After sub First is $first\n\n";
当我运行我的代码时,替换没有发生,我的$ first保持不变,即first.txt再次出现。我错过了什么?我在像http://www.regexr.com/这样的在线正则表达式测试器中使用了我的正则表达式,我的正则表达式匹配第一个“或”和“/或”之间的多行字符串。 为什么perl不喜欢我的正则表达式?
答案 0 :(得分:2)
通过尝试捕获所有这些XML片段,您在比赛中过于复杂。以下正则表达式是一种更简单的替换方法:
$first =~ s#(<or>\s+)<value field="id">.*?</value>(\s*</or>)#$1$content$2#sm;
我使用了修饰符s
和m
,它们允许匹配多行,并允许.
包含换行符;因此,我们可以替换<or>
开始和结束标记之间的任意数量的行。我还使用#
作为我的正则表达式的分隔符,所以我没有必须逃避XML关闭标记中的斜杠。
有关正则表达式的更多信息,请参阅perlre,特别是有关修饰符的信息。
答案 1 :(得分:0)
与往常一样,使用正则表达式操作XMNL是一个非常糟糕的想法。因此,您可以看到执行操作是多么简单&#34;正确&#34;,此程序使用XML::LibXML
模块执行您所要求的操作。
创建XML解析器对象并用于解析second.xml
文件的每一行,将它们放入@fragments
数组中以供以后使用
解析first.xml
文件,findnodes
找到所有or
个元素,其中第一个元素用removeChildNodes
清空,并再次填充每一行来自@fragments
使用appendChild
最后,使用toString
格式化XML并打印
use strict;
use warnings;
use 5.010;
use autodie;
use XML::LibXML;
my $parser = XML::LibXML->new(no_blanks => 1);
open my $fh, '<', 'second.xml';
my @fragments = map {
chomp;
$parser->parse_balanced_chunk($_);
} <$fh>;
close $fh;
my $xml = $parser->load_xml(location => 'first.xml');
my @or_nodes = $xml->findnodes('//or');
$or_nodes[0]->removeChildNodes;
$or_nodes[0]->appendChild($_) for @fragments;
print $xml->toString(1);
<强>输出强>
<?xml version="1.0"?>
<metric>
<baseFilter>
<and>
<or>
<value field="id">3333</value>
<value field="id">4444</value>
</or>
<or>
<value field="resolution"/>
</or>
</and>
</baseFilter>
</metric>
答案 2 :(得分:0)
首先将新值加载到数组中。
然后使用$INPLACE_EDIT
使用如下逻辑编辑文件:
#!/usr/bin/perl
use strict;
use warnings;
my @newvals = qw(3333 4444);
while (<DATA>) {
s{<value field="id">\K\w+(?=</value>)}{shift @newvals}e if @newvals;
print;
}
__DATA__
<metric>
<baseFilter>
<and>
<or>
<value field="id">1111</value>
<value field="id">2222</value>
</or>
<or>
<value field="resolution" />
</or>
</metric>
输出:
<metric>
<baseFilter>
<and>
<or>
<value field="id">3333</value>
<value field="id">4444</value>
</or>
<or>
<value field="resolution" />
</or>
</metric>