## The Scalar Range Operator

I have been playing with the scalar range operator, and it confused me so much that I started experimenting and reading about it, and here is what I wrote up.

### Numeric Values

This operator, in scalar context, has two forms that act as a bistable or flip-flop. The first form looks like this:Thisif ($left .. $right) { ... }

`if`statement works as follows: The condition evaluates false until

`$left`evaluates true. Then the

`$left`condition is ignored, and the condition continues to evaluate true until

`$right`evaluates true, at which point the condition evaluates false, and it goes back to check

`$left`. In this way, it flip-flops between waiting for the left side to evaluate true, and then waiting for the right side to evaluate true. Very strange, until you see it operating in a program:

This program prints out the second and third line of the data. A numeric value in the scalar range operator is therefore compared towhile (<DATA>) { print if 2 .. 4; } __DATA__ first second third fourth fifth __OUTPUT__ second third fourth

`$.`.

### Regular Expressions

This example shows the use of two regular expressions in the scalar range operator:It prints out lines in the data beginning with the line that first evaluates true (while (<DATA>) { print if /start/ .. /end/; } __DATA__ ignore start first second third end ignore start fourth fifth end ignore __OUTPUT__ start first second third end start fourth fifth end

`start`), until the line that next evaluates true (

`end`). All the lines that are not bracked by

`start/end`pairs are ignored. Note that this data contains two blocks of lines that are between

`start`and

`end`markers, and the lines outside those ranges are ignored.

### Numeric and Regular Expressions

Combining a numeric and a regex in the range operator also works as expected. In this example, the lines from`$. == 1`until

`$_ =~ /end/`are printed.

while (<DATA>) { print if 2 .. /end/; } __DATA__ first second third end ignore __OUTPUT__ second third end

### Exluding Markers

In order to exclude lines that contain`start`and

`end`, a further condition is required. The condition is that the result returned by the scalar range operator must be neither

`1`(representing

`$.`of 1), nor must it contain

`E`. When the operator encounters the line that evaluates true for the right-hand-side, it's return value is (in the example below)

`5E0`. This number evaluates to

`5`, but contains that

`E`, which is the indicator that this line terminates the right-hand-side of the operator. This code prints all the lines

*between*the

`start`and

`end`lines:

while (<DATA>) { if (my $num = /start/ .. /end/) { print unless $num == 1 || $num =~ /E/; } } __DATA__ ignore start first second third end ignore start fourth fifth end ignore __OUTPUT__ first second third fourth fifth

To better illustrate that, this program prints out that value, for all
lines between `start` and `end`:

while (<DATA>) { if (my $num = /start/ .. /end/) { print $num, "\t", $_; } } __DATA__ ignore start first second third end ignore start fourth fifth end ignore __OUTPUT__ 1 start 2 first 3 second 4 third 5E0 end 1 start 2 fourth 3 fifth 4E0 end

### Markers on Same Line

This example places both the`start`and

`end`tokens on the same line. From the output, it can be seen that the combined line has a value of

`1E0`which satisfies the test as both the first and last line of the desired input.

while (<DATA>) { if (my $num = /start/ .. /end/) { print $num, "\t", $_; } } __DATA__ ignore start first second end ignore start third end ignore __OUTPUT__ 1 start 2 first 3 second 4E0 end 1E0 start third end

### The Scalar ... Operator

The other form of the scalar range operator is`...`. This operator performs as the

`..`operator does, but lines that meet one criteria are not also evaluated for the other. So a line that contains both

`start`and

`end`is only evaluated once - in this case for the

`start`line, causing this data to be considered as having a

`start`but not an

`end`, meaning that the data is not properly treated in this example.

This form of the scalar range operator is more efficient only if it is known that both conditions can never be true on the same line.while (<DATA>) { if (my $num = /start/ ... /end/) { print "$num\t$_"; } } __DATA__ ignore start first end ignore __OUTPUT__ 1 start first end 2 ignore

**Update:** Changed examples to not include so many edge cases. Thanks to hossman.

Back to
Tutorials