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

5

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

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

我想将该值增加0.04,并保持XML的格式不变。我知道可以使用Perl或awk脚本实现,但是我在分离数字时遇到了困难。
5个回答

4
如果你使用带有xsltproc命令的盒子,我建议你使用XSLT来完成这个任务。
对于Perl解决方案,我建议使用DOM。可以查看这篇文章:使用Perl进行DOM处理
话虽如此,如果你的XML文件按照可预测的方式生成,那么以下的简单方法可能会起作用:
perl -pe 's#(<VALUE DECIMAL_VALUE=")([0-9.]+)(" UNIT_TYPE="percent"/>)#"$1" . ($2 + 0.4) . "$3"#e;'

我认为你的意思是“($2 + 0.4)”而不是“($2 * 0.4)”。 - j_random_hacker

3
如果您绝对确定您的XML格式永远不会更改,属性顺序固定,并且确实可以正确获得数字的正则表达式... 那么可以选择非解析器(parser)的解决方案。
个人建议使用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;
  }

嘿,我一直在从事依赖于Twig的项目。感谢你编写了如此出色的模块! - PEZ
谢谢。我想知道XML::Twig是否就像Perl对LISP一样是XSLT的一种替代品(请参见http://xkcd.com/224/)。 - mirod
我认为你的意思是 "$decimal_value += 0.4" 而不是 "$decimal_value *= 0.4"。 - j_random_hacker
也许那是我的错。=)无论如何,我现在已经修复了它。 - PEZ

2

这将从标准输入接收输入,输出到标准输出:

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

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

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);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接