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

Greetings I have a text field of the following format.

blank line
blank line
blank line
some text
blank line
some more text

I wish to remove all blank lines up to the first piece of text.e.g.
some text
blank line
some more text

The text is being passed in the following way

sub logit {
my($line) = shift(@_);
$line =~ s/\0//g;
print OUTF $line
}

Using print if (!/^$/) removes all blank lines which I don't want.
Any help appreciated

Replies are listed 'Best First'.
Re: blank lines up to a point
by Random_Walk (Prior) on Sep 15, 2004 at 10:21 UTC

    This may be the code you are looking for, uses the .. flip-flop operator which is true when the first condition is satisfied then remains true until the itteration after the second condition is true. With the second condition here never going to be true it flips but dont flop !

    #!/usr/local/bin/perl -w use strict; while (<DATA>) {&logit ($_)} sub logit { my $line = shift @_; $line =~ s/\0//g; return unless (/\S/..0); print $line } __DATA__ Some data Some more Some later data

    Cheers,
    R.

      Never say never :)   0 as a second condition can be true.
      use strict; use warnings; my $firsttime = 1; my $line1 = <DATA>; print neverflop(); $firsttime = 0; my $line2 = <DATA>; print neverflop(); scalar tell(STDIN); print neverflop(); print neverflop(); sub neverflop { ($firsttime .. 0) ? "flip" : "flop"; } __DATA__ line1 line2 line3 __END__ Output: flipflipflipflop

        I get an error from this unless I alter the tell line to my $discard=tell(STDIN); then indeed it gives the advertised output (I am on an old perl version here, client requirements)

        ./flipflop Useless use of tell in void context at ./flipflop line 14. perl -v This is perl, version 5.005_03 built for sun4-solaris ...after the above edit.... root@tivpre-master:/home/robinp # ./fixedflop flipflipflipflop

        that aside how does this work ? the docco says tell normaly returns -1 against STDIN, what dark juju is going on to make 0 true and what else could I use that I can trust never to be true ?

        Updated

        It took some digging but I've got it now. the binary range operator .. will compare a given constant value to the value of the current input line number $. (actualy int(EXPR)==int($.) I was naively using 0 in its meaning of false and you cunningly reset $. to 0 (with tell(STDIN)) so 0 got matched. I offer up a fixed sub to avoid this gotcha.
        sub logit { local $.=1; my $line = shift @_; $line =~ s/\0//g; return unless (/\S/..0); print $line }

        Many Thanks,
        R.

        This works as a quirk of the flip/flop operator. From the documentation "If either operand of scalar ``..'' is a constant expression, that operand is implicitly compared to the $. variable, the current line number." The statement scalar tell(STDIN) must set $. = 0 (although I don't know why) changing the line from scalar tell(STDIN); to $. = 0; gives the same result.

        use strict; use warnings; my $firsttime = 1; my $line1 = <DATA>; print neverflop(); $firsttime = 0; my $line2 = <DATA>; print neverflop(); #scalar tell(STDIN); $. = 0; print neverflop(); print neverflop(); sub neverflop { my $statecount = ($firsttime .. 0); ($firsttime .. 0) ? "flip$statecount\t" : "flop$statecount\t"; } __DATA__ line1 line2 line3 __END__ flip1 flip2 flip3E0 flop

        PJ
        use strict; use warnings; use diagnostics; (if needed)
      The flip-flop use is interesting. I would have done:
      my $line; do { $line = <DATA>; } until ($line=~m/\S/); do { s/\0//g; print $line; } while($line=<DATA>); __DATA__ Some text More text And so one and on...
      It's one less operation per iteration of the second loop, which would be ever-so-slightly faster on large files (I think).
      --
      $me = rand($hacker{perl});

        I think the reason I used the flip flop was so the subroutine held state as the OP was asking for a subroutine to provide this behaviour when being passed one line at a time (and because it was a bit fun). Your method does look faster for large files (and probably any size files) but I think you are cheeting a bit by using execution flow to hold state.

        I propose a less interesting subroutine that is probably as fast as yours. Once $flipped is set there is only one check made in each sub call due to short circuiting the rest of the or when the first side is true.

        #!/usr/local/bin/perl -w use strict; my $flipped=0; sub logit { my $line=shift; $line=~s/\0//g; return unless ($flipped or ($line=~/\S/ and ++$flipped)); print $line; } while (<DATA>) {&logit ($_)} __DATA__ we dont really need this again but here it is anyway

        Cheers,
        R.

      Thanks for the info.
Re: blank lines up to a point
by gothic_mallard (Pilgrim) on Sep 15, 2004 at 12:44 UTC
    Why do you need the s/\0//g btw? If you can get away without that then you can get the logit() sub down to:
    sub logit{ print OUTF if (/\S/..0); }
    Works the same way just without being so verbose.
Re: blank lines up to a point
by ambrus (Abbot) on Sep 15, 2004 at 16:24 UTC

    If I understand you correctly, the logit subroutine gets called at the code from different places, one line at a time. Thus, you need something like this (untested). I avoid the flipflop operator here, as it's somewhat confusing for me.

    { my $seentext; sub logit { my($line) = @_; $line=~s/\0//g; $line=~/\S/ and $seentext = 1; print OUTF $line; } }