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

I am using a more complex version of
while (<FILE>) { print; if (/$pattern/) { &do_some_other_thing; } }
is there a way I can manipulate $_ or some other variable that can find a pattern in a line, and then grab information from the previous line(s)? I may encounter difficulty in storing the whole file in an array of lines (it's about 4 MB).

Replies are listed 'Best First'.
Re: read lines... wait
by japhy (Canon) on Jan 29, 2000 at 13:03 UTC
    You could use a hash to hold the tell() positions of the lines in the file. We use a hash instead of an array, because we don't want to HAVE to hold 10,000 elements just to have $array9999.
    open FILE, "file" or die "can't open file: $!"; $position{1} = 0; while (<FILE>) { # $. holds line number of file being read from $position{$.+1} = tell(FILE); # record byte offset # do stuff with $_ # access a previous line by doing: if (CONDITION) { seek FILE, $position{$LINE_NUMBER}, 0; $data = <FILE>; # ... # when done, get back to where you were seek FILE, $position{$.+1}, 0; } } close FILE;
    Incidentally, dlc, unshift() requires an explicit list of expressions to prepend to an array, and does not default to prepending $_. -- Jeff Pinyan, japhy@pobox.com http://www.pobox.com/~japhy/
Re: read lines... wait
by dlc (Acolyte) on Jan 28, 2000 at 22:09 UTC

    you need to explicitly save the lines you'll want. you'll probably not need to save more than a few, so this is not really a big deal. define a list, and keep them as you go:

    sub process { print 'foo'; }
    my @oldlines = ();
    my $LINES_TO_KEEP = 10;
    while(<>) {
        # drop the entry on the bottom, and add $_ to the top
        unshift @oldlines;
        scalar(@oldlines)>$LINES_TO_KEEP && pop @oldlines;
    
        # do your processing here. call process first unless you
        # want @oldlines to hold the unmodified version of the
        # line
        process($_);
    }
    
Re: read lines... wait
by jbert (Priest) on Jan 31, 2000 at 16:19 UTC
    If you only want to keep knowledge of the last 'few' lines, you can keep a rolling array. Something like...
    $num_to_keep = 10; while( <FILE> ) { push @saved_lines, $_; ...do your stuff... shift @saved_lines if @saved_lines > $num_to_keep; }
    Any good (1st perl monk post...:-)