二項演算子の ".." は範囲演算子で、使われるコンテキストによって異なる動作 をする 2 つの演算子を合わせたものです。リストコンテキストでは、左の値か ら右の値まで (1 づつ) 数えあげた値からなる配列を返します。これは、for (1..10) のようなループを書くときや、配列のスライス演算を行なうときに便利 です。現状のインプリメントでは、テンポラリの配列が作られるので:
for (1 .. 1_000_000) { # プログラム }
のようなことを書くと、メモリを使い果たして、悲惨な結果になりかねませんの で注意してください。
スカラコンテキストで使われたときには、".." はブール値を返します。この演 算子は、フリップフロップのように 2 値安定で、sed や awk や多くのエディタ での行範囲 (コンマ) 演算子をエミュレートするものとなります。各々の ".." 演算子がそれぞれに独立して自分のブール状態を管理します。はじめは、左被演 算子が偽である間、演算全体も偽となっています。範囲演算子は、いったん左被 演算子が真になると、右被演算子が真である間、真を返すようになります。右被 演算子が偽になると、演算子も偽を返すようになります。(次に範囲演算子が評 価されるまでは、偽とはなりません。(awk でのように) 真となった、その評価 の中で右被演算子をテストし、偽とすることができますが、1 度は真を返すこと になります。(sed でのように) 次に評価されるまで、右被演算子をテストした くなければ、2 個のドットの代わりに 3 つのドット ("...") を使ってください。 右被演算子は、演算子の状態が「偽」である間は評価されることがなく、左被演 算子は、演算子の状態が「真」である間は評価されることがありません。優先順 位は、|| と && の少し下です。偽としては空文字列が返され、真としては (1 から始まる) 順に並んだ数値が返されます。この通し番号は、新たに範囲が始ま るごとにリセットされます。範囲の最後の数字には、文字列 "E0" がお尻につけ られます。これは、数値としては何の影響もありませんが、範囲の終わりで何か 特別なことをしたい場合に、目印として使うことができます。範囲の始まりで何 かしたい場合には、通し番号が 1 よりも大きくなるのを待っていればよいでしょ う。スカラの ".." の被演算子が数値リテラルであるときは、その被演算子は暗 黙に、変数 $. (現行番号)と比較されることになります。例:
スカラ演算子として:
if (101 .. 200) { print; } # 101 行目から 200 行目を印字 next line if (1 .. /^$/); # ヘッダをスキップし、 s/^/> / if (/^$/ .. eof()); # 本文を引用する。
リスト演算子として:
for (101 .. 200) { print; } # $_ を 100 回、印字する @foo = @foo[$[ .. $#foo]; # コストがかかるが何もしない @foo = @foo[$#foo-4 .. $#foo]; # 最後の 5 要素のスライス
(リストコンテキストでの) 範囲演算子は、被演算子が文字列であるときには、 マジカルインクリメントの機能を使います。大文字すべての配列を得るのに
@alphabet = ('A' .. 'Z');
と書けますし、
$hexdigit = (0 .. 9, 'a' .. 'f')[$num & 15];
と書けば、16 進の数字が得られますし、
@z2 = ('01' .. '31'); print $z2[$mday];
とすれば、0 付きの日付が得られます。マジカルインクリメントによって得られ る値の中に指定した最終値にちょうど一致するものが見つからないような場合に は、マジカルインクリメントによって得られる次の値の文字列長が、最終値とし て指定した値のものより長くなるまでインクリメントが続けられます。
Go to the first, previous, next, last section, table of contents.