The .
. range operator is really two
different operators depending on the context.
In scalar context, .
. returns a Boolean
value. The operator is bi-stable, like an electronic flip-flop, and
emulates the line-range (comma) operator of sed,
awk, and various editors. Each scalar
.
. operator maintains its own Boolean state. It is
false as long as its left operand is false. Once the left operand is
true, the range operator stays true until the right operand is true,
after which the range operator becomes false
again. The operator doesn't become false until the next time it is
evaluated. It can test the right operand and become false on the same
evaluation as the one where it became true (the way
awk's range operator behaves), but it still
returns true once. If you don't want it to test the right operand
until the next evaluation (which is how sed's
range operator works), just use three dots (…
)
instead of two. With both .
. and
…
, the right operand is not evaluated while the
operator is in the false state, and the left operand is not evaluated
while the operator is in the true state.
The value returned is either the null string for false
or a sequence number (beginning with 1
) for true.
The sequence number is reset for each range encountered. The final
sequence number in a range has the string "E0
"
appended to it, which doesn't affect its numeric value, but gives you
something to search for if you want to exclude the endpoint. You can
exclude the beginning point by waiting for the sequence number to be
greater than 1. If either operand of scalar .
. is a
numeric literal, that operand implicitly compared to the
$
. variable, which contains the current line number
for your input file. Examples:
if (101 .. 200) { print; } # print 2nd hundred lines next line if (1 .. /^$/); # skip header lines s/^/> / if (/^$/ .. eof()); # quote body
In list context, .
. returns a list of values
counting (by ones) from the left value to the right value. This is
useful for writing for (1..10)
loops and for doing
slice operations on arrays:
for (101 .. 200) { print; } # prints 101102…199200 @foo = @foo[0 .. $#foo]; # an expensive no-op @foo = @foo[ -5 .. -1]; # slice last 5 items
If the left value is greater than the right value, a null list
is returned. (To produce a list in reverse order, see the
reverse
operator.)
If its operands are strings, the range operator makes use of the magical autoincrement algorithm discussed earlier.[4] So you can say:
@alphabet = ('A' .. 'Z'),
to get all the letters of the (English) alphabet, or:
$hexdigit = (0 .. 9, 'a' .. 'f')[$num & 15];
to get a hexadecimal digit, or:
@z2 = ('01' .. '31'), print $z2[$mday];
to get dates with leading zeros. You can also say:
@combos = ('aa' .. 'zz'),
to get all combinations of two lowercase letters. However, be careful of something like:
@bigcombos = ('aaaaaa' .. 'zzzzzz'),
since that will require lots of memory. More precisely, it'll need space to store 308,915,776 scalars. Let's hope you allocated a very large swap partition. Perhaps you should consider an iterative approach instead.
[4] If the final value specified is not in the sequence that the magical increment would produce, the sequence continues until the next value is longer than the final value specified.