Regex 在perl中使用正则表达式替换xml标记内的多行字符串
我已经尝试了一段时间,以使这项工作,但没有运气。这是我的文本文件(first.txt)Regex 在perl中使用正则表达式替换xml标记内的多行字符串,regex,perl,Regex,Perl,我已经尝试了一段时间,以使这项工作,但没有运气。这是我的文本文件(first.txt) ,my regex匹配第一个“或”和“/或”之间的多行字符串。 为什么perl不喜欢我的正则表达式?您试图捕获所有这些XML片段,这将使比赛中的事情变得过于复杂。以下正则表达式是执行替换的一种简单得多的方法: $first =~ s#(<or>\s+)<value field="id">.*?</value>(\s*</or>)#$1$content$2#sm
,my regex匹配第一个“或”和“/或”之间的多行字符串。
为什么perl不喜欢我的正则表达式?您试图捕获所有这些XML片段,这将使比赛中的事情变得过于复杂。以下正则表达式是执行替换的一种简单得多的方法:
$first =~ s#(<or>\s+)<value field="id">.*?</value>(\s*</or>)#$1$content$2#sm;
$first=~s#(\s+).*(\s*)#$1$content$2#sm;
我使用了修饰符s
和m
,它们允许多行匹配,并允许
包含新行字符;因此,我们可以替换
开始和结束标记之间的任意数量的行。我还使用了#
作为正则表达式的分隔符,这样我就不必费劲地转义XML close标记中的斜杠
有关正则表达式,特别是修饰符的更多信息,请参阅。一如既往,使用正则表达式操作XMNL是一个非常糟糕的主意。为了让您看到“正确”做事是多么简单,此程序使用模块执行您的要求
- 创建一个XML解析器对象,用于解析
second.XML
文件的每一行,将它们放入@fragments
数组中供以后使用
- 解析
first.xml
文件,然后findnodes
查找所有或元素,其中第一个元素用removeChildNodes
清空,并使用appendChildNodes
再次填充@fragments
中的每一行
- 最后,使用
toString
对XML进行格式化并打印
使用严格;
使用警告;
使用5.010;
使用自动模具;
使用XML::LibXML;
my$parser=XML::LibXML->new(无空格=>1);
打开my$fh,“首先将新值加载到数组中
然后使用$INPLACE\u 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>
#/usr/bin/perl
严格使用;
使用警告;
my@newvals=qw(333344444);
而(){
s{\K\w+(?=)}{shift@newvals}e如果@newvals;
印刷品;
}
__资料__
1111
2222
产出:
<metric>
<baseFilter>
<and>
<or>
<value field="id">3333</value>
<value field="id">4444</value>
</or>
<or>
<value field="resolution" />
</or>
</metric>
3333
4444
你不能只搜索#.*\s+.*m
并替换它吗?我搜索第一个“或”和“/或”之间的字符串的原因是我可能有50个值字段行,我需要替换为第二个.txt中的任何内容。你可能应该编辑你的问题,说明在这种情况下……我觉得有人需要提及
#!/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 =~ s#(<or>\s+)<value field="id">.*?</value>(\s*</or>)#$1$content$2#sm;
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>
#!/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>