in reply to blank lines up to a point

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.

Replies are listed 'Best First'.
Re^2: blank lines up to a point
by ysth (Canon) on Sep 15, 2004 at 10:51 UTC
    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)
        $. is stored per-filehandle, and automatically refers to the last input file. Any of readline, tell, seek, sysseek, or eof will change the last input file.

        You could just use:

        /\S/ .. my $false
        instead.
Re^2: blank lines up to a point
by radiantmatrix (Parson) on Sep 15, 2004 at 19:41 UTC
    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.

Re^2: blank lines up to a point
by Anonymous Monk on Sep 15, 2004 at 12:28 UTC
    Thanks for the info.