Perl: использование функции триггера и извлечение данных из блока чтения - PullRequest
2 голосов
/ 17 декабря 2011

У меня есть массив с именем @mytitles, который содержит много заголовков, таких как, скажем, title1, title2 и так далее.У меня есть файл с именем "Superdataset", в котором есть информация, относящаяся к каждому названию.Тем не менее, информация, относящаяся к title1, может состоять из 6 строк, а информация для title2 может быть 30 строками (это случайное значение).Каждый фрагмент информации (для titlex) начинается с "Reading titlex" и заканчивается "Done reading titlex".

Из этих строк информации каждого заголовка мне нужно извлечь некоторые данные.Я думаю, что мне повезло, что эти данные, которые мне нужны, находятся в 2 строках перед "Done reading titlex" каждый раз

Так что мой "Superdataset" выглядит так:

Reading title1  
 random info line1
 random info line2
 random info line3
 random info line4
 random info line5
 my earnings are 6000
 my expenses are 1000
Done reading title1
Reading title2
 random info line6
 random info line7
 random info line8
 random info line9
 random info line10
 random info line11
 random info line12
 random info line13
 random info line14
 my earnings are 11000
 my expenses are 9000
Done reading title2

Мне нужнообщая сумма расходов и общая сумма заработка.Какие-либо предложения?PS-массив имеет сложные имена, а не что-то простое, как titlex

Ответы [ 3 ]

0 голосов
/ 17 декабря 2011

Используя оператор 'range', вы можете сделать:

#!/usr/bin/env perl
use strict;
use warnings;
use Data::Dumper;
my $begin_stanza = qr/^Reading/i;
my $endof_stanza = qr/^Done reading/i;
my ( $title, @lines );
my ( $value, $total_earnings, $total_expenses );
while (<DATA>) {
    chomp;
    if ( m{$begin_stanza} .. m{$endof_stanza} ) {
        if ( m{$begin_stanza\s+(.+)} ) {
            $title = $1;
            @lines = ();
            next;
        }
        if ( m{$endof_stanza} ) {
            ($value) = ( $lines[0] =~ m{(\d+)} );
            $total_earnings += $value;
            ($value) = ( $lines[1] =~ m{(\d+)} );
            $total_expenses += $value;
            print join "\n", $title, @lines, "\n";
            next;
        }
        shift @lines if @lines == 2;
        push  @lines, $_;
    }
}
printf "Total Earnings = %7d\n", $total_earnings;
printf "Total Expenses = %7d\n", $total_expenses;
__DATA__
Reading title1
 random info line1
 random info line2
 random info line3
 random info line4
 random info line5
 my earnings are 6000
 my expenses are 1000
Done reading title1
Reading title2
 random info line6
 random info line7
 random info line8
 random info line9
 random info line10
 random info line11
 random info line12
 random info line13
 random info line14
 my earnings are 11000
 my expenses are 9000
Done reading title2

... что дает:

title1
 my earnings are 6000
 my expenses are 1000

title2
 my earnings are 11000
 my expenses are 9000

Total Earnings =   17000
Total Expenses =   10000
0 голосов
/ 19 декабря 2011

Если вы не можете предсказать, какой будет строка перед соответствующими строками, оператор триггера не принесет много пользы в виде оптимизации. Я думаю, что было бы проще работать с буферным массивом и просто сопоставить строку после заработка и расходов.

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

my @buffer;
my ($earnings, $expenses);

for my $line (<DATA>) {
    shift @buffer if @buffer > 2;
    push @buffer, $line;

    next if $line !~ /^Done reading/;

    $earnings += $1 if $buffer[0] =~ /(\d+)$/;
    $expenses += $1 if $buffer[1] =~ /(\d+)$/;
}
print "Total earnings: $earnings\n";
print "Total expenses: $expenses\n";

__DATA__
Reading title1  
 random info line1
 random info line2
 random info line3
 random info line4
 random info line5
 my earnings are 6000
 my expenses are 1000
Done reading title1
Reading title2
 random info line6
 random info line7
 random info line8
 random info line9
 random info line10
 random info line11
 random info line12
 random info line13
 random info line14
 my earnings are 11000
 my expenses are 9000
Done reading title2

Выход:

Total earnings: 17000
Total expenses: 10000
0 голосов
/ 17 декабря 2011

Вот первый шаг при переводе данных в удобную форму.

use warnings;
use strict;
use autodie;

my $input_filename = 'example';
open my $input, '<', $input_filename;
my %data;
{
  my $current_title;

  while(<$input>){
    chomp;
    if( /^Reading (.*?)\s*$/ ){ # start of section
      $current_title = $1;
    }elsif( not defined $current_title ){ # outside of any section
      # invalid data
    }elsif( /^Done reading (.*)/ ){ # end of section
      die if $1 ne $current_title;
      $current_title = undef;
    }else{ # add an element of section to array
      push @{ $data{$current_title} }, $_;
    }
  }
}
close $input;

Использование созданной структуры данных для определения общих доходов и расходов.

my( $earnings, $expenses );
for my $list( values %data ){
  for( @$list ){
    if( /earnings are (\d+)/ ){
      $earnings += $1;
    }elsif( /expenses are (\d+)/ ){
      $expenses += $1;
    }
  }
}

print "earnings $earnings\n";
print "expenses $expenses\n";

Вместо этого распечатать его в форме, более удобной для компьютера.

use YAML 'Dump';
print Dump \%data;
---
title1:
  - ' random info line1'
  - ' random info line2'
  - ' random info line3'
  - ' random info line4'
  - ' random info line5'
  - ' my earnings are 6000'
  - ' my expenses are 1000'
title2:
  - ' random info line6'
  - ' random info line7'
  - ' random info line8'
  - ' random info line9'
  - ' random info line10'
  - ' random info line11'
  - ' random info line12'
  - ' random info line13'
  - ' random info line14'
  - ' my earnings are 11000'
  - ' my expenses are 9000'
...