如何使用awk或Perl递增大型XML文件中的数字?

时间:2009-01-15 20:15:49

标签: perl awk

我有一个XML文件,其中包含以下行:

            <VALUE DECIMAL_VALUE="0.2725" UNIT_TYPE="percent"/>

我想将此值增加.04并保持XML的格式。我知道这可以使用Perl或awk脚本,但是我很难用表达式来隔离数字。

5 个答案:

答案 0 :(得分:4)

如果你在xsltproc命令的盒子上,我建议你使用XSLT。

对于Perl解决方案,我会选择使用DOM。请查看此DOM Processing with Perl文章。

那就是说。如果您的XML文件以可预测的方式生成,那么天真如下的东西可以起作用:

perl -pe 's#(<VALUE DECIMAL_VALUE=")([0-9.]+)(" UNIT_TYPE="percent"/>)#"$1" . ($2 + 0.4) . "$3"#e;'

答案 1 :(得分:3)

如果您完全确定XML的格式永远不会改变,那么属性的顺序是固定的,那么您确实可以获得正确数字的正则表达式...然后选择基于非解析器的解决方案。

我个人会使用XML :: Twig(也许是因为我写了它; - )。它将XML作为XML处理,同时仍然尊重文件的原始格式,并且在开始工作之前不会将其全部加载到内存中。

以下未经测试的代码:

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

use XML::Twig;

XML::Twig->new( # call the sub for each VALUE element with a DECIMAL_VALUE attribute
                twig_roots => { 'VALUE[@DECIMAL_VALUE]' => \&upd_decimal },
                # print anything else as is
                twig_print_outside_roots => 1,
              )
         ->parsefile_inplace( 'foo.xml');

sub upd_decimal
  { my( $twig, $value)= @_; # twig is the XML::Twig object, $value the element
    my $decimal_value= $value->att( 'DECIMAL_VALUE');
    $decimal_value += 0.4;
    $value->set_att( DECIMAL_VALUE => $decimal_value);
    $value->print;
  }

答案 2 :(得分:2)

这将输入stdin,输出到stdout:

while(<>){
 if( $_ =~ /^(.*DECIMAL_VALUE=\")(.*)(\".*)$/ ){
  $newVal = $2 + 0.04;
  print "$1$newVal$3\n";
 }else{
  print $_;
 }
}

答案 3 :(得分:0)

类似于以下内容将起作用。如果有额外的间距,可能需要调整,但这留给读者练习。

function update_after(in_string, locate_string, delta) {
    local_pos = index(in_string,locate_string);
    leadin    = substr(in_string,0,local_pos-1);
    leadout   = substr(in_string,local_pos+length(locate_string));
    new_value = leadout+delta;
    quote_pos = index(leadout,"\"");
    leadout   = substr(leadout, quote_pos + 1);
    return leadin locate_string new_value"\"" leadout;
}

/^ *\<VALUE/{
    print  update_after($0, "DECIMAL_VALUE=\"",0.4);
}

答案 4 :(得分:0)

这里是gawk

awk '/DECIMAL_VALUE/{
 for(i=1;i<=NF;i++){
    if( $i~/DECIMAL_VALUE/){
        gsub(/DECIMAL_VALUE=|\042/,"",$i)
        $i="DECIMAL_VALUE=\042"$i+0.4"\042"
    }
 }
}1' file