## 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:

` if ($left .. $right)
{
...
}
`

This

`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:

` while (<DATA>)
{
print if 2 .. 4;
}
__DATA__
first
second
third
fourth
fifth
__OUTPUT__
second
third
fourth
`

This program prints out the second and third line of the data.
A numeric value in the scalar range operator is therefore compared to

`$.`.

### Regular Expressions

This example shows the use of two regular expressions in the scalar
range operator:

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

It prints out lines in the data beginning with the line that first evaluates
true (

`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.

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

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.

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