in reply to how to check for a word in a file and if found remove that line, the above line and the below line from the file.

You need to keep a buffer containing the lines you may need to throw away and print lines from the buffer when you know that they won't be thrown away. This stuff is tricky to get right because you have to correctly handle special cases for start up and ending conditions. Here's one way to do it:

use strict; use warnings; my $kPreLines = 1; my $kPostLines = 1; my $skipping; my @bufferedLines; while (defined (my $line = <DATA>) || @bufferedLines) { push @bufferedLines, $line if defined $line; while (@bufferedLines && $skipping) { shift @bufferedLines; --$skipping; } print shift @bufferedLines while @bufferedLines > $kPreLines + 1; next if !@bufferedLines; if ($bufferedLines[-1] =~ /XXXXX/) { $skipping = $kPostLines; @bufferedLines = (); next; } next if defined $line; print @bufferedLines; last; } __DATA__ QQQQQ PPPPP XXXXX is my name YYYYY KKKKK UUUUU BBBBB CCCCCC XXXXX is what I play KKKKK NNNNN

Prints:

QQQQQ KKKKK UUUUU BBBBB NNNNN
Premature optimization is the root of all job security
  • Comment on Re: how to check for a word in a file and if found remove that line, the above line and the below line from the file.
  • Select or Download Code

Replies are listed 'Best First'.
Re^2: how to check for a word in a file and if found remove that line, the above line and the below line from the file.
by Discipulus (Canon) on Jan 20, 2016 at 09:37 UTC
    I was sure it would be easier with splice but i falled in the 'modifying an array while iterating over it' pitfall..
    To avoid a copied data I needed to undef some value and grep for defined values when printing the copy output.. anyway it works.
    I have modified the DATA a little to be easier to follow
    use strict; use warnings; my @lin = <DATA>; map { $lin[$_] and $lin[$_] =~/XXXXX/ ? $_ == 0 ? splice @lin,0,2,undef,undef : $_ == $#lin ? splice @lin,$_-1,2,undef,undef : splice @lin,$_-1,3,undef,undef,undef : 1 } 0..$#lin; print "$_" for grep {defined} @lin; __DATA__ XXXXX Aoooo XXXXX is my name Boooo 11111 22222 33333 Coooo XXXXX is what I play Doooo 44444 # OUTPUT 11111 22222 33333 44444


    L*
    There are no rules, there are no thumbs..
    Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.

      If you are going to read the whole file into memory you also allow for the following solution which seems more simple and direct than working with splice.

      use strict; use warnings; my $file_content = do { local $/ = undef; <DATA>; }; $file_content =~ s/ (?:.*\n)? ^X{5}.*\n (?:.*\n)?//xmg; print $file_content; __DATA__ XXXXX Aoooo XXXXX is my name Boooo 11111 22222 33333 Coooo XXXXX is what I play Doooo 44444
      Ron
Re^2: how to check for a word in a file... -- who spot the trick?
by Discipulus (Canon) on Jan 20, 2016 at 10:54 UTC
    Who spot the trick?
    use strict; use warnings; my @unv; my $pos; while (<DATA>){push @unv,$.-1,$.,$.+1 if /XXXXX/;$pos=(tell DATA)-leng +th $_ unless $pos} seek DATA,$pos,0; while (<DATA>) {print unless $.-__LINE__ ~~ @unv} __DATA__ XXXXX Aoooo XXXXX is my name Boooo 11111 22222 33333 Coooo XXXXX is what I play Doooo 44444 # OUTPUT 11111 22222 33333 44444
    If you spot the trick please explain it to... me!
    L*

    UPDATE: the trick can be avoided with a cleaner solotion assigning to $.
    use strict; use warnings; my @unv; my $pos; while (<DATA>){push @unv,$.-1,$.,$.+1 if /XXXXX/;$pos=(tell DATA)-leng +th $_ unless $pos} seek DATA,$pos,0; $.=0; while (<DATA>) {print unless $. ~~ @unv}

    L*

    There are no rules, there are no thumbs..
    Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.
Re^2: how to check for a word in a file.. -- oneliner
by Discipulus (Canon) on Jan 20, 2016 at 11:38 UTC
    Less tricky than the above oneliner version:
    # file used below has the same content of the previous example's DATA +token<P> perl -e "open $fh,$ARGV[0];while(<$fh>){push @unv,$.-1,$.,$.+1 if /XXX +XX/}seek $fh,0,0;while(<$fh>){print unless ++$index ~~ @unv}" file 11111 22222 33333 44444

    i was not able to resolve to use perl -lne because i've encountered some problem using seek ARGV even if in a BEGIN block.

    L*
    There are no rules, there are no thumbs..
    Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.
Re^2: how to check for a word in a file and if found remove that line, the above line and the below line from the file.
by BillKSmith (Monsignor) on Jan 21, 2016 at 03:30 UTC
    Another special case is when /xxxxx/ appears on two (or more) consecutive lines.
    Bill
Re^2: how to check for a word in a file and if found remove that line, the above line and the below line from the file.
by ikegami (Patriarch) on Jan 22, 2016 at 16:45 UTC