Make exclusive flip-flop operators

In Respect the global state of the flip flop operator, you saw some examples of the .. scalar operator. The flip-flop operator returns false until its lefthand side is true. Once the lefthand side is true, the flip-flop operator returns true until its righthand side is true. Once the righthand side is true, the flip flop operator returns false:

while( <> ) {
	print if /START/ .. /END/;
	}

This means that this code will display lines once it finds one that matches START, including the line that matches, and will keep displaying lines until it finds one matching END, including that matching line. The short way to say that is that the flip-flop is inclusive. It includes its endpoints.

What if you wanted an exclusive flip-flop operator though, so you didn’t get the starting and ending lines? Your code would work the same way, but without displaying the line that flips or flops the match? Lucky for you, the flip-flop returns more than just true. Modify the earlier code to capture the return value and print it before the line:

while( <> ) {
	my $rc;
	print "$rc: $_" if $rc = /START/ .. /END/;
	}

__END__
Ignore this
Ignore this too
START
Show this
And this
Also this
END
Don't show this
Or this

The output prepends the return value of the flip-flop operator for each line:

1: START
2: Show this
3: And this
4: Also this
5E0: END

The flip-flop operator returns the sequence number, starting with 1, for each line. For the last line, it appends E0. You may not have know this, but it’s all in perlop’s section on Range Operator. To exclude the endpoints, you adjust the if:

use strict;

while(  ) {
	my $rc;
	print "$rc: $_" if( $rc = /START/../END/ and $rc !~ /(^1|E0)$/ );
	}

__END__
Ignore this
Ignore this too
START
Show this
And this
Also this
END
Don't show this
Or this

Now the output is exclusive:

2: Show this
3: And this
4: Also this

Once you know about the sequence numbers, you have more control over the lines that you extract between your endpoints. Perhaps you only want the even lines:

	print "$rc: $_" if( $rc = /START/../END/ and ! ($rc % 2) );

Or just the odd lines:

	print "$rc: $_" if( $rc = /START/../END/ and ($rc % 2) );

Things to remember

  • The flip-flop operator is inclusive
  • While true, the flip-flop operator returns a sequence number, and the last line appends E0 to that number
  • You can create an exclusive sequence with a compound conditional

One thought on “Make exclusive flip-flop operators”

  1. Putting the assignment inline with the conditional makes the code more complex and isn’t necessary. Just assign it beforehand:

    my $rc = /START/../END/;

    And you could extract the last sequence of digits:

    my ($rc) = (/START/../END/) =~ /([0-9]+)\z/;

    This will yield the original value of $rc on all iterations except the last one, where it matches the “0” from the appended “E0”.

    With this, the conditional becomes simply this:

    print "$rc: $_" if $rc > 1;

Comments are closed.