0

我需要以这种格式转换 .txt 文件的一部分(首先通过匹配“SchDay”)

<SchDay>
  <Name>School Occup WD</Name>
  <Type>Fraction</Type>
  <Hr index="0">0</Hr>
  <Hr index="1">0</Hr>
  <Hr index="2">0</Hr>
  <Hr index="3">0</Hr>
  <Hr index="4">0</Hr>
  <Hr index="5">0</Hr>
  <Hr index="6">0</Hr>
  <Hr index="7">0.05</Hr>
  <Hr index="8">0.75</Hr>
  ....

看起来像这样(值是第一位的,“步骤”只需要定义 2 个末端):

0.00, 0.00,

0.00, 6.00,    <- end of step

0.05, 7.00,

0.75, 8.00,

...

ETC

这是我到目前为止所拥有的:

open (OUTFILE, ">C:/begperl/parts/all1.txt")|| die "Can't open it";

my @files = glob ("*.txt");

for (@files) {

    open (INFILE, $_) || die "can't open infile";
    @lines = <INFILE>;
    my %answer;
    $regex = '<SchDay';
    for my $idx (0..$#lines) {
    if ($lines[$idx] =~ /$regex/) {
        for $ii (($idx + 3)..($idx + 26)){
        {$answer{$ii} = ($lines[$ii]);}
        }
    }
    foreach $key (sort keys %answer) { print OUTFILE "$answer{$key}\n" }
    }
close (INFILE);}

所以我有我想要的线条。现在我只需要提取数字,包括小数点,然后删除具有相同值的连续小时。

4

1 回答 1

1

您的文档具有 XML 结构。通过使用适当的 XML 解析器来利用它会好得多。XML::Twig允许您轻松地隔离 XML 文档中您感兴趣的部分。在这种情况下,我们想要的只是<Hr>出现在元素中的<SchDay>元素:

my $parser = XML::Twig->new(
    twig_roots => { 'SchDay/Hr' => \&do_print },
);

这只是告诉解析器为a中的每个调用do_printsub 。将使用两个参数调用:我们刚刚创建的解析器实例和元素。用于访问索引属性的值,并获取属性的文本,并格式化和打印它们。这是脚本:<Hr><SchDay>do_print$element->att('index')$attr->text

#!/usr/bin/env perl

use strict;
use warnings;

use XML::Twig;

my $parser = XML::Twig->new(
    twig_roots => { 'SchDay/Hr' => \&do_print },
);

$parser->parse(\*DATA);

sub do_print {
    my $parser = shift;
    my $element = shift;

    printf "%.02f,%.02f,\n",
        $element->text,
        $element->att('index'),
    ;
    $parser->purge;
    return;
}

__DATA__
<SchDay>
  <Name>School Occup WD</Name>
  <Type>Fraction</Type>
  <Hr index="0">0</Hr>
  <Hr index="1">0</Hr>
  <Hr index="2">0</Hr>
  <Hr index="3">0</Hr>
  <Hr index="4">0</Hr>
  <Hr index="5">0</Hr>
  <Hr index="6">0</Hr>
  <Hr index="7">0.05</Hr>
  <Hr index="8">0.75</Hr>
</SchDay>

输出:

0.00, 0.00,
0.00, 1.00,
0.00, 2.00,
0.00, 3.00,
0.00, 4.00,
0.00, 5.00,
0.00, 6.00,
0.05, 7.00,
0.75, 8.00,

至于你的代码需要修复什么……以下是我希望能帮助你写出更好的 Perl 的几点:

open (OUTFILE, ">C:/begperl/parts/all1.txt")|| die "Can't open it";
  • 不要使用裸字文件句柄,例如OUTFILE. 它们是包变量,这意味着它们会受到远距离的影响。相反,在最小的适用范围内声明一个词法变量,如下所示:

     my $filename = 'C:/begperl/parts/all1.txt';
    
     open my $outfile, '>', $filename
          or die "Failed to open '$filename': $!";
    
  • 请在循环中命名循环变量for

     for my $input_file (@files) {
          open my $input, '<', $input_file
              or die "Failed to open '$input_file': $!";
    
  • 当逐行处理可以时,不要啜饮。也就是说,不要@lines = <INFILE>;一次读取文件的所有行。

  • 不要使用诸如 the326below 之类的神奇常量。相反,给他们起名字。例如:

           use Const::Fast;
           const my $HR_BEGIN => 3;
           const my $HR_END   => 26;
    

但是,还是太脆弱了。如果<Hr>元素的行数发生变化怎么办?毕竟,这是一个 XML 文档,您可以轻松地获得下一批

<Hr index="5">
   0.00
</Hr>

那你怎么办呢?

于 2013-08-16T11:31:39.050 回答