cutter has asked for the wisdom of the Perl Monks concerning the following question:

Hi, I am trying to learn Perl by doing and it is getting like I am sewing my parachute together in the air. What I am trying to do is extract a specific string from a file and write it to another file. For example what I want to extract from the sample data is the entry calendar: Calendar_1_test and the dates following it.
calendar: Calendar_1_test 11/01/03 11/02/03 calendar: Calendar_2_test 01/02/03 01/04/03 calendar: Calendar_3_test 03/01/03 03/02/03
Some code I have tried follows. It does not find the dates associated with the calender entry.I have looked at the PerlFAQ and just about had my head explode reading the Doc for Parse-RecDescent module. Any help apprecated.
$file="test_file.txt"; $StrSearch = "calendar: Calendar_2_test"; open TEST, $file; while (<TEST>) { if (/$StrSearch/) { print "1\n";} else { if (/$StrSearch(.*?)calendar/qs){ print "1\n";}

Replies are listed 'Best First'.
Re: How do I extract data?
by jdporter (Paladin) on Dec 26, 2002 at 19:38 UTC
    For something like this, one approach is to use a simple state machine.

    In my solution below, I read the entire file into a hash, keyed by the second word on the "calendar:" lines.
    my %entries; # key=calendar name; value=array(ref) of dates. my $calendar; my @dates; sub finish_pending_entry { if ( defined $calendar ) { $entries{$calendar} = [ @dates ]; } # re-init the state data: $calendar = undef; @dates = (); } while (<>) { chomp; if ( /calendar: (.*)/ ) { finish_pending_entry(); # possibly none, if this is the fi +rst line. $calendar = $1; } else { push @dates, $_; } } finish_pending_entry(); # possibly none, if file was empty.
    Now, if you want the dates for calendar "Calendar_2_test", say, you'd simply access     @{  $entries{'Calendar_2_test'} }

    jdporter
    ...porque es dificil estar guapo y blanco.

      Of course, you might like a more object-oriented approach:
      { package CalendarEntry; sub new { my $pkg = shift; bless { dates => [], name => shift, }, $pkg } sub add_date { my $self = shift; push @{ $self->{'dates'} }, @_; } } # end CalendarEntry. my @entries; # array of CalendarEntry objects. my $entry; while (<>) { chomp; if ( /calendar: (.*)/ ) { defined $entry and push @entries, $entry; $entry = new CalendarEntry $1; } else { $entry->add_date( $_ ); } } defined $entry and push @entries, $entry;
      Now you have an array of CalendarEntry objects in @entries. You can convert that into a hash, with key = entry name and value = array(ref) of dates, like so:      my %entries = map { $_->{'name'} => $_->{'dates'} } @entries; Then you can look things up as before:     @some_dates = @{ $entries{'Calendar_2_test'} };

      jdporter
      ...porque es dificil estar guapo y blanco.

Re: How do I extract data?
by Wonko the sane (Curate) on Dec 26, 2002 at 19:56 UTC
    Something like this would also do the trick.

    If your record names are going to really be numeric in nature
    there are advantages to storing the data in an array rather than a hash as shown here.

    #!/usr/local/bin/perl -w use strict; use Data::Dumper; my %records; { local $/ = 'calendar: '; # record separator. while ( <DATA> ) { push( @{$records{$1}}, split(/\n+|calendar: /) ) if ( s/Calendar_([0-9]+)_test\n+// ); } } print Dumper( \%records ); __DATA__ calendar: Calendar_1_test 11/01/03 11/02/03 calendar: Calendar_2_test 01/02/03 01/04/03 calendar: Calendar_3_test 03/01/03 03/02/03

    Outputs:

    :!./test.pl $VAR1 = { '1' => [ '11/01/03', '11/02/03' ], '2' => [ '01/02/03', '01/04/03' ], '3' => [ '03/01/03', '03/02/03' ] };
    Once the data has been parsed into the hash or array, you can simply access
    the dates you want and print them to a file.

    print FILE @{$records{1}}

    Best Regards,
    Wonko

Re: How do I extract data?
by poj (Abbot) on Dec 26, 2002 at 19:59 UTC
    I'm not sure what you think the print "1\n" does but if you want to output to a file use
    use strict; use warnings; my $file="test_file.txt"; my $StrSearch = "calendar: Calendar_1_test"; open TEST, $file; open OUT,">result.txt"; while (<TEST>) { if (/$StrSearch/) { print OUT; while (<TEST>){ if (/^calendar/){ last; } else { print OUT; } } } } close TEST; close OUT;

    poj
Re: How do I extract data?
by cutter (Acolyte) on Dec 26, 2002 at 20:15 UTC

    Thanks to all. I had a feeling that I was going in the wrong direction and your examples sure have helped me get back on course. Now for a busy weekend, as of course this is for a project due before the new year.

    Cutter