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
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;