2011-12-17 1 views
2

У меня есть массив под названием @mytitles, который содержит много названий, таких как, например, title1, title2 и т. Д. У меня есть файл под названием «Superdataset», который содержит информацию, относящуюся к каждому заголовку. Однако информация, связанная с title1, может иметь 6 строк, а информация для title2 может быть 30 строк (ее случайных). Каждый фрагмент информации (для titlex) начинается с «Reading titlex» и заканчивается «Done reading titlex».Perl: Использование функции флип-флопа и извлечения данных изнутри блока.

Из этих строк информации каждого заголовка мне нужно извлечь некоторые данные. Я думаю, что его счастье, что эти данные мне нужно в 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

ответ

0

Вот первый проход, связанный с данными в полезную форму.

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' 
+0

спасибо Брэд. Не могли бы вы вкратце объяснить, что здесь происходит - мне, возможно, придется его подстроить. Мои данные и все очень грязные. – user1102982

+0

@ user1102982 Мое первоначальное сообщение просто показало, как разделить данные на хэш массивов. Я добавил пример кода, чтобы показать, как его можно использовать и как он структурирован. –

0

Использование оператора '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

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

#!/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