PL/Iの世界へようこそ!INDEX関数で文字列検索をマスターしよう
こんにちは。メインフレームの世界へようこそ。
普段JavaやCOBOLに慣れ親しんでいる方にとって、PL/Iは少し「古風で威圧的な古本屋」のように見えるかもしれません。でも安心してください。PL/Iは、C言語の柔軟性とCOBOLの堅牢さを併せ持つ、非常に「人間味のある」言語なんです。
今回は、基幹システムのバッチ処理で避けては通れない「文字列検索」の要、`INDEX`関数について紐解いていきましょう。
—
1. PL/Iの基本構造:まずは「お作法」を確認
PL/Iのプログラムは、実はとてもシンプルです。入り口(エントリーポイント)は一つだけ。`OPTIONS(MAIN)`という呪文を添えるのがお約束です。
/i
MY_PROGRAM: PROCEDURE OPTIONS(MAIN);
/ ここに処理を書いていきます /
DCL SEARCH_STR CHAR(20) INIT(‘IBM MAINFRAME’);
/ 処理の最後には必ずENDを忘れずに /
END MY_PROGRAM;
`DCL`(DECLARE)は変数宣言です。COBOLの`PICTURE`句に慣れていると最初は戸惑うかもしれませんが、「型と長さを決めるだけ」と捉えれば簡単です。
—
2. INDEX関数:文字列検索の「眼」
文字列の中から特定のキーワードを探すとき、PL/Iでは`INDEX(source, target)`関数を使います。
- source: 探される側の文字列
- target: 探したい文字列
- 戻り値: 見つかった場合は「最初の文字位置(1から始まる)」、見つからない場合は「0」
現場でよくある「落とし穴」
COBOLの`INSPECT`やJavaの`indexOf`に慣れていると、この「見つからないと0を返す」という仕様を忘れがちです。特に大規模なデータ処理では、0を適切にハンドリングしないと、意図しないオフセットでデータが切り取られ、夜間バッチが異常終了(通称:アベンド)する原因になります。
/i
DCL TARGET_POS FIXED BIN(15);
DCL SOURCE_STR CHAR(50) INIT(‘TRANSACTION_ID:12345’);
/ 検索実行 /
TARGET_POS = INDEX(SOURCE_STR, ‘:’);
/ 0が返ってきたらエラー処理へ飛ばすのが鉄則です /
IF TARGET_POS = 0 THEN DO;
PUT SKIP LIST(‘警告: 区切り文字が見つかりません’);
END;
ELSE DO;
/ 見つかった位置以降を切り出す /
PUT SKIP LIST(‘IDの開始位置は: ‘ || TARGET_POS);
END;
—
3. なぜINDEX関数は大規模データで効率的なのか?
メインフレームの世界では、数十万行のレコードを秒単位で処理することが求められます。ここで重要なのが「メモリの賢い使い方」です。
PL/Iの`INDEX`関数は、コンパイラがハードウェア(CPU)の命令セットを最大限活用するように最適化されています。自前でループを書いて一文字ずつ比較するよりも、圧倒的に高速です。
パフォーマンス向上のためのヒント
- 固定長と可変長を使い分ける: 検索対象が常に同じ長さなら、`CHAR(n)`(固定長)を使いましょう。`VARYING`属性をつけると柔軟になりますが、わずかながらメモリ管理のオーバーヘッドが発生します。
- 無駄な宣言を避ける: ループの中で毎回`INDEX`を使う場合、引数となる変数が「再評価」されないように注意してください。定数やループの外で決定できる変数は、あらかじめ`INIT`しておくのが効率化の第一歩です。
—
4. 初学者へのアドバイス:怖がらなくて大丈夫
PL/Iが「難しい」と感じる最大の理由は、その多機能さです。「何でもできてしまう」がゆえに、記述の自由度が高すぎて迷子になりやすいのです。
しかし、現場で使う機能は実は限られています。
1. まずは `INDEX` で位置を特定する
2. `SUBSTR` 関数で必要な部分を切り出す
3. 戻り値の「0」を必ず条件分岐でケアする
この3ステップを意識するだけで、あなたの書くコードは驚くほど堅牢になります。
メインフレームのコードは、先人たちが何十年もかけて守り抜いてきた「ビジネスの血流」そのものです。今日からあなたも、その血流を止めない、頼れるシステムアーキテクトの一員です。
もしコードを書いていて「何かがおかしい」と感じたら、いつでも戻ってきてください。この古くて新しい言語の奥深さを、また一緒に紐解いていきましょう。
それでは、良いバッチライフを!
