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

发布于 2024-07-13 02:30:07 字数 206 浏览 4 评论 0原文

我有一个包含以下行的 XML 文件:

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

我想将此值增加 0.04 并保持 XML 的格式不变。 我知道使用 Perl 或 awk 脚本可以做到这一点,但我在使用表达式来隔离数字时遇到困难。

I have an XML file with the following line:

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

I would like to increment this value by .04 and keep the format of the XML in place. I know this is possible with a Perl or awk script, but I am having difficulty with the expressions to isolate the number.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

剩余の解释 2024-07-20 02:30:08

如果您绝对确定 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;
  }

If you are absolutely sure that the format of your XML will never change, that the order of the attributes is fixed, that you can indeed get the regexp for the number right... then go for the non-parser based solution.

Personally I would use XML::Twig (maybe because I wrote it ;--). It will process the XML as XML, while still respecting the original format of the file, and won't load it all in memory before starting to work.

Untested code below:

#!/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;
  }
荒人说梦 2024-07-20 02:30:08

这需要 stdin 上的输入,输出到 stdout:

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

This takes input on stdin, outputs to stdout:

while(<>){
 if( $_ =~ /^(.*DECIMAL_VALUE=\")(.*)(\".*)$/ ){
  $newVal = $2 + 0.04;
  print "$1$newVal$3\n";
 }else{
  print $_;
 }
}
爱格式化 2024-07-20 02:30:08

类似下面的东西会起作用。 如果有额外的间距,可能需要调整,但这留给读者作为练习。

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

Something akin to the following will work. It may need tweaking if there is extra spacing, but that is left as an exercise for the reader.

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);
}
‖放下 2024-07-20 02:30:08

这是呆呆的

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

here's 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
指尖上的星空 2024-07-20 02:30:07

如果您使用的是 xsltproc 命令,我建议您使用 XSLT。

对于 Perl 解决方案,我会选择使用 DOM。 查看这篇使用 Perl 处理 DOM 文章。

就是这样说的。 如果您的 XML 文件是以可预测的方式生成的,那么像下面这样简单的东西就可以工作:

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

If you're on a box with the xsltproc command in place I would suggest you use XSLT for this.

For a Perl solution I'd go for using the DOM. Check this DOM Processing with Perl article out.

That said. If your XML file is produced in a predictable way something naïve like the following could work:

perl -pe 's#(<VALUE DECIMAL_VALUE=")([0-9.]+)(" UNIT_TYPE="percent"/>)#"$1" . ($2 + 0.4) . "$3"#e;'
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文