ファンシーレンジオペレーター

これは、啓示を含まない別の記事であることを警告しなければなりません。 perldoc全体を暗記しているスーパーギークにとっては、それは絶対に役に立たないので、親愛なるスーパーギークにとっては、このすべてがドックにあることを知らずに通り過ぎることができます。 私はすでにそれを知っています。 :-)私の記事は、perldoc全体を完全にマスターしていない、またはマスターしたが、理解していない、または理解していないが覚えていない人を対象としています。



多くの人が、 ..



(2ポイント)と書かれたいわゆる範囲演算子について知っていると思い..



これを使用すると、一連の連続した要素から配列をすばやく作成できます。 たとえば、次のコードは35個の数字の配列を作成します:3、4、5、...、37:

my @arr = 3 .. 37 ;



数字に加えて、文字列を使用できます。この場合、配列要素を生成するために、いわゆるマジックインクリメントが実行されます(たとえば、文字の範囲を指定できます: 'a' .. 'z'



)。



ただし、範囲演算子はスカラーコンテキストでも使用でき、オペランドとしてブール式を受け入れ、ブール結果を返します。 そして、ここで最も興味深い部分が始まります。これは、 状態を持つ演算子であるためです。 演算の結果は、左オペランドと右オペランドの値だけでなく、この式の呼び出し履歴にも依存します!



もちろん、範囲演算子の結果を計算するための方法論を説明する正式な定義をここで与えることができますが、本質を理解する前に5〜6回再読するためにこの正式な定義が個人的に必要でした。 したがって、他の方法を使用することをお勧めします。 ファイルを1行ずつ処理しており、このファイル内のいくつかのブロックに対して特定のアクションを実行する必要があると想像してください(たとえば、複数行のコメントをスキップします)。 ブロックとは何ですか? これは、ブロックの開始と終了を示す2つのマーカーで囲まれた、ほぼ任意の行のセットです。 明確にするために、C / C ++のスタイルでコメントを取ります(そして、簡単にするために、コメントと便利なコマンドは同じ行に隣接できないと想定しています)。 処理するコードの例を次に示します。

01: int i = 10 , j, k;

02: for (j = i; j < 2 * i; ++j) {

03: /*

04:

05: -

06: . */


07: k = j * j;

08: printf ( "Result[%d]: %d\n" , j, k);

09: /* . */

10: }





上記のテキストのコメント化されていない行をすべて表示するコードを記述します。 Cプログラマーは行ごとの処理で何をしますか? たとえば、現在の状態を格納する変数を作成します。コメント内にあるかどうか(つまり、マーカー " /*



"を読み取りますが、まだ " */



"を満たしていません)。この変数の値に応じて、出力または画面に次の行を表示しないでください。また、目的のタイプのマーカーが見つかったときに、値をタイムリーに変更することを忘れないでください。 そして、パールのプログラマーは何をしますか? そして、彼は範囲演算子を使用して、次のようなものを書きます。

while ( my $line = <FILE>) {

if (($line =~ m/^\s*\/\*/) .. ($line =~ m/\*\/\s*$/)) {

# $line - , .

}

else {

# $line - , .

print $line;

}

}





このコードは何をしますか? つまり、まさに必要なものです。 ここで、範囲演算子の左側のオペランドはコメントの先頭、右側から末尾に対応しています。 そして、範囲演算子自体は、コードを実行する過程で、左のオペランドの操作から右の操作までの「間隔」にある場合にのみtrueを返します。 したがって、演算子はその名前を完全に正当化します。つまり、論理範囲を設定します。



これで、正式な定義(公式のperlopドキュメントからの抜粋の無料翻訳)を提供できます。

各演算子には、独自のブール状態が含まれます。 左のオペランドがfalseの場合、値は「false」です。 左側のオペランドが真になるとすぐに、範囲演算子は真の値を受け入れ、右側のオペランドが真の値を受け入れるまでそのままです。 その後、範囲演算子は再び偽の値を想定します。
次に、このやや曖昧な定義を通常の範囲と一致させる魔法を整理してみましょう。 これを行うには、デバッガーとして自分自身を紹介し、入力ファイルを1行ずつ読み取って、プログラムを順番に実行します。 簡潔にするために、左および右のオペランド(コメントの開始と終了に一致するブール式)をMBおよびME (マーカー開始/マーカー終了の略)として示します。

  1. int i = 10 , j, k;





    この行では、 MBMEの両方がfalseを返すため、 ..



    演算子もfalseを返します。 したがって、この行はコメントではありません。
  2. for (j = i; j < 2 * i; ++j) {





    同様に、 MBMEはfalseを与えるため、式全体もfalseになります。
  3. /*





    そして最後に、 MBがトリガーされます。 は嘘のままです。 定義によれば、この時点で、範囲演算子は真の値を想定しており、読み取り行がコメントであるという結果が得られます。






  4. この行では、式MBMEは再び何も検出せず、falseを返します。 ただし、オペレーターは既に真の状態に切り替えているため、 MEが真の値を受け入れるまで、その状態のままになります。 したがって、再び真実がわかります。つまり、この行はコメントです。
  5. -





    ここで、 MEはまだ真になっいないため、オペレーターは真実を伝え続け..



    つまり、コメントの最後に到達していません。
  6. . */





    そしてここで、最後に、 MEがトリガーされます。 範囲演算子はため息をついて最後に真実を伝え、その後元の状態に戻ります。 しかし、この行については、複数行コメントの構造に関するアイデアとよく相関する真実が得られます。この行は最終的なものですが、コメントの一部であり、上記のTKに従って出力されるべきではありません。
  7. k = j * j;





    景品は終わりました、先生。 MBMEは両方とも偽であり、演算子は元の状態にあり、偽を返すため、この行はコメントではありません。
  8. printf ( "Result[%d]: %d\n" , j, k);





    ...このように。 同じ理由で。
  9. /* . */





    しかし、この作品は非常に興味深いです。MBMEの両方が同時にここで動作します。 何が変わりますか? はい、一般的には何もありません。 演算子..



    は、定義上、将来のためにこれを記憶して真実を返しますが、第2オペランドもtrueであるため、すぐに初期状態に戻ります。コメントはすぐに開始および終了します。
  10. }





    この行はMBまたはMEのいずれにもキャッチされません。オペレーターは何とかスイッチバックできるため、ここでfalseを返し、この行をコメントなしとしてマークします。
この簡単な例が、何が何であるかを理解するのに役立つことを願っています。 実際、演算子には、私たちが発明したCプログラマーが明示的に入力することを強制された非常にローカルな状態変数と、その値の管理をいじくり回すことが含まれています。



もちろん、範囲演算子の範囲は、行単位または単語単位のワードプロセッシングに限定されるものではなく、すべてはあなたの想像力によってのみ決定されます。 たとえば、その助けを借りて、多少の基本チェックよりも難しい条件によって境界が設定されている場合、データ配列の一部の範囲を決定することができます。



ここで、2点演算子に加えて..



も3点演算子( ...



)があることを説明する価値があり...



。 2ポイントの1つとまったく同じように動作しますが、1つの違いがあります。演算子の初期状態の最初のオペランドが真の値をとるとき、2番目のオペランドは無視されます。 したがって、演算子...



を使用しようとした場合、ファイルの9行目のコメントは完全とは見なされませんが、ファイルの最後まで(より正確には、コメントの最後の次のマーカーが表示されているが、ファイル内で単にそのような行の例はありません)。 使用例として、処理中のブロックの開始と終了が同じ特別な行で指定されている状況を挙げることができます。 ここでの2点演算子は無力で、3点演算子は完璧です。



最後に、少し表記を読みたいと思います。コードの読みやすさと自己コメントを忘れないでください。 それがその中にあるという理由だけで、言語の機会を使用する必要はありません。 実際、特定のブロックがいくつかのデータのシーケンシャル処理で明確に割り当てられている場合、この演算子を使用すると、このブロックを短時間で、明確かつエレガントに記述することができます。 しかし、範囲演算子をどこにでも押し付け始めたとしても、それが非常に独創的で珍しく、誰も持っていないからといって、私には信じられません。



All Articles