AnnaSchumann
AnnaSchumann

Reputation: 1271

Printing both the matched line and lines ±1 upon regex match (1-liner)

How can I print a matched line as well as a line before and after it? I've currently got:

perl -lane 'print if $F[3] > 100000 && $F[2] =~ /^C$/ && print $last; $last = $_'

Which is capable of printing both the matched line and a line before it - but I am not sure how to include the line after.

Upvotes: 2

Views: 72

Answers (3)

ikegami
ikegami

Reputation: 385655

The following handles overlapping matches. $N is the number of lines to printe before and after the matching lines.

perl -lane'
   BEGIN { $N = 1 }
   if ($F[3] > 100000 && $F[2] =~ /^C$/) { print for splice(@buf), $_; $next=$N }
   elsif ($next) { --$next; print }
   else { push @buf, $_; splice @buf, 0, -$N }
'

Since we know $N = 1, we can simplify the above into the following:

perl -lane'
   if ($F[3] > 100000 && $F[2] =~ /^C$/) { print for splice(@buf), $_; $next=1 }
   elsif ($next) { $next=0; print }
   else { @buf = $_ }
'

Upvotes: 1

Arunesh Singh
Arunesh Singh

Reputation: 3535

You can also use seek and tell and rewind back one line for overlapping matches:

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

open my $fh ,'<', 'input' or die "unable to open file: $!\n";
my $last="";
while(<$fh>){
        my @b=split;
        if(($b[3] > 100000) && ($b[2] =~ /^C$/)){
          print $last if $last;
          print;
          my $t=tell $fh;
          print scalar <$fh>,"\n";
          seek $fh,$t,0; #rewind          
        }
        $last=$_;
}
close($fh);

Upvotes: 0

choroba
choroba

Reputation: 241828

You can read the next line from the file directly using scalar <>:

perl -lane 'print, print scalar <>
                if $F[3] > 100000 && $F[2] =~ /^C$/
                && print $last;
            $last = $_' input

Or use a sliding window for overlapping matches:

perl -ane 'BEGIN { @b = map [], 1 .. 3 }
           sub out {
               shift @b;
               if ($b[1][3] > 100_000 && $b[1][2] =~ /^C$/) {
                   print for map $_->[-1], @b;
               }
            }
            push @b, [@F, $_];
            out()
            }{ out()  # Process the last line
           ' input

Upvotes: 4

Related Questions