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

Hi monks,

I would like to know how to delete a line and the next line if they occur in order.

As in Assume

First line is cat

second line is dog.

If cat is followed by dog in the preceding line, I want to delete both lines.

But if dog is followed by cat, I want to keep both the lines.

for instance if input file (input.txt) has
dog cat dog dog cat goat
the output file (output.txt) will be will be
dog dog cat goat
I think I should buffer some lines, but I am not sure how to proceed. Any help will be greately appreciated.

Replies are listed 'Best First'.
Re: If line is followed by line, delete both lines
by Athanasius (Archbishop) on Sep 15, 2016 at 07:16 UTC

    Hello Ganesh Bharadwaj1,

    If your input lines are always paired, then Marshall’s approach is probably the best. Otherwise, your logic will need to be a bit more complicated. For example:

    use strict; use warnings; my $previous_line; my $exclude = 0; while (my $current_line = <DATA>) { if (defined $previous_line) { if ($previous_line =~ /cat/ && $current_line =~ /dog/) { $exclude = 1; } else { emit_line($previous_line) unless $exclude; $exclude = 0; } } $previous_line = $current_line; } emit_line($previous_line) unless $exclude; sub emit_line { my ($line) = @_; print $line if defined $line; } __DATA__ dog hippopotamus cat dog dog cat goat

    Output:

    17:11 >perl 1695_SoPW.pl dog hippopotamus dog cat goat 17:11 >

    Hope that helps,

    Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

Re: If line is followed by line, delete both lines
by Marshall (Canon) on Sep 15, 2016 at 07:03 UTC
    I'm not quite sure what you want.
    Looks like you are processing the input DATA as pairs of lines. You print both lines of the pair unless the specific "dog followed by cat" line sequence of the pair occurs? This is a bit different than deleting 2 lines if "cat" just happens to follow just any "dog". That is possible, just doesn't appear to be what you are asking for.

    this reproduces your desired printout. You tell me how close this is to what you really want...

    update: But if dog is followed by cat, I want to keep both the lines. You desired output shows the reverse, e.g. cat following dog causes the 2 lines to be deleted.

    The basic idea below (with variance for other implementation variations). The basic idea is that it is "hard" to "undo a write" (go backwards and say "oh, I didn't mean that). Keep track of stuff until you are sure that you want to keep it, then write it out. Once it is gone, you can forget about it and start thinking about the next pair of things.

    I suspect that you will need to generate a better thought out example if this code doesn't do what you want.

    #/usr/bin/perl use strict; use warnings; my @lines; while (my $cur_line = <DATA>) { push @lines, $cur_line; next if @lines <2; print @lines unless ($lines[0] =~ /dog/ and $lines[1] =~ /cat/); @lines = (); } =prints dog dog cat goat =cut __DATA__ dog cat dog dog cat goat
Re: If line is followed by line, delete both lines
by Marshall (Canon) on Sep 15, 2016 at 09:09 UTC
    This part of your spec is confusing (at least to me)...
    1. If cat is followed by dog in the preceding (next?) line, I want to delete both lines.
    2. But if dog is followed by cat, I want to keep both the lines.
      What the purpose of this extra condition?
    In this sequence, does line 3 being "cat" somehow overrule, Rule #1 and keep line #2, dog and even perhaps line #1 in the output?
    1 cat 2 dog 3 cat
    Rule #1 says this should be "cat" (dog cannot follow cat):
    3 cat
    But Rule #2, seems to indicate that sometimes cat can indeed follow dog - maybe the confluence or Rule 1 and Rule 2 causes "1 cat" to be deleted, but somehow "2 dog" is saved from deletion by Rule #2? How this would work is certainly not clear to me.:
    2 dog 3 cat
    Or maybe even no changes at all happen due to conflicting rules?!
    1 cat 2 dog 3 cat
    The English and code examples are not sufficient for me to understand what to code that will exactly solve your problem. The requirements are just not clear to me.

    Please correct the English and elaborate on the examples.

Re: If line is followed by line, delete both lines
by Anonymous Monk on Sep 15, 2016 at 14:31 UTC
    #!/usr/bin/perl # http://perlmonks.org/?node_id=1171814 use strict; use warnings; $_ = join '', <DATA>; s/^.*cat.*\n.*dog.*\n//gm; print; __DATA__ dog cat dog dog cat goat