When you hear yourself saying "I need to know what comes n lines before XYZ", you should be thinking "I need to stash n previous lines while I iterate through the file." When you hear yourself saying, "I need to know what comes after XYZ until PDQ is found.", you should be thinking of how to identify state (ie, how to keep track of having found the trigger). You can keep track of state with a variable, or you can do it by flowing into a different branch of code. This snippet accomplishes your goal by stashing two lines at all times (clearing them only after XYZ is found), and by flowing into a different branch when XYZ has been found, until PDQ shows up.

As I mentioned above, this is one of several common ways of dealing with state.

use strict; use warnings; my $find = 'jack'; my $trigger_re = qr{^name\s+$find\b}; my $finally_re = qr(^lastname\s+\p{Alpha}+\b); my @stash; while( my $line = <DATA> ) { chomp $line; if( $line =~ $trigger_re ) { print "$_\n" for @stash; @stash = (); print $line, "\n"; while ( my $next = <DATA> ) { if( $next =~ $finally_re ) { print $next; last; } } } else { push @stash, $line; while( @stash > 2 ) { shift @stash; } } } __DATA__ start id 10 address Richmond name jack xxxxx aaaaa lastname black yyyy zzzzz id 11 address Central name rick cccccc dddddd lastname hanna eeeee yyyyy id 12 address denver name jack sssss tttttt lastname strong rrrrr mmmmm id 13 address Virginia name mick aaaaaaa ooooooo lastname jagger gggggg hhhhhh id 14 address Maine name rick sssss sssss lastname stewart ssssss ffffff end

The output is...

id 10 address Richmond name jack lastname black id 12 address denver name jack lastname strong

If the stash hasn't received two lines ahead of "name jack", it will quietly just print however many it accumulated (max 2). If the "lastname" never shows up, it will quietly flow through the end of the file. This may not be what you want; it's possible that you'll want to just carp about a malformed record the moment the next "name" shows up. That's pretty easy to implement, so I'll leave it to you if you find it advantageous. Similarly, it's a simple check to verify that two lines are stored in @stash prior to printing, and it would be easy to carp a warning about a malformed record there as well.

I build the regexes outside of the loop just to keep the loop code as simple (and general) as possible. This has the added efficiency benefit of assuring that the regex that contains variable interpolation will only be compiled once rather than each time through the loop.


Dave


In reply to Re: get n lines before or after a pattern by davido
in thread get n lines before or after a pattern by darklord_999

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.