如何从提取的行中读取数字(删除重复的数字)

时间:2013-08-16 11:04:49

标签: regex perl xml-parsing extract

我需要以这种格式转换.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,

...

这是我到目前为止所做的:

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

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

1 个答案:

答案 0 :(得分:1)

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

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

这只是告诉解析器为do_print中的每个<Hr>调用<SchDay>子。将使用两个参数调用do_print:我们刚刚创建的解析器实例和元素。使用$element->att('index')访问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>;一次性读取文件的所有行。

  • 请勿使用下面的326等神奇常量。相反,给他们起名字。例如:

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

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

进行下一批
<Hr index="5">
   0.00
</Hr>

那你做什么?