【PL/I深掘り】文字列操作の鉄則:INDEXとVERIFYを使いこなす技術
メインフレームの現場で、JCLの変更よりも骨が折れるのが、何十年も前に書かれたPL/Iソースコードの保守だ。特に文字列操作。若いエンジニアが`SUBSTR`と`INDEX`を駆使してスパゲッティのようなロジックを組んでいるのを見ると、つい「そこはもっとスマートにやれるぞ」と肩を叩きたくなる。
今日は、PL/Iにおける文字列検索の要、『INDEX』と『VERIFY』について、実務でハマりやすい罠と最適解を共有しよう。
—
1. 識別子と予約語の「自由」が招く悲劇
まず前提として、PL/Iという言語の特異性を理解しておく必要がある。CやJavaと違い、PL/Iには「厳密な意味での予約語」が存在しない。`INDEX`という関数名であっても、変数名として使えてしまうのだ。
「え、じゃあ `DCL INDEX CHAR(10);` と書いたらどうなるの?」
答えは単純。そのスコープ内では、組み込み関数の`INDEX`は使えなくなる。コンパイラは「プログラマが自分で定義した変数」を優先するからだ。もし既存のバッチ処理で「なぜかコンパイルエラーにもならずに結果がおかしい」という事態に直面したら、まずコード全体で関数名が変数名として隠蔽(オーバーライド)されていないかを確認してほしい。これが、PL/Iの現場で最初に見るべき「基本のキ」だ。
—
2. INDEXとVERIFY:使い分けの黄金律
文字列操作で最も多用するのがこの二つだが、その挙動を曖昧にしているエンジニアが多い。
- INDEX(string, pattern):
「特定の文字列がどこから始まるか」を探す。見つからなければ「0」を返す。これは基本だ。
- VERIFY(string, pattern):
「指定したパターンに含まれない文字がどこにあるか」を探す。つまり、妥当性チェックの強力な武器だ。
実践的なコード例
VSAMファイルから読み込んだ固定長レコードの特定のフィールドを解析するケースを想定しよう。
/i
/ VSAMファイルから読み込んだレコードの解析用バッファ /
DCL REC_BUFFER CHAR(80) VAR;
DCL POS FIXED BIN(15);
/
- 1. INDEXの活用: 特定の区切り文字を探す
- ‘ ‘ (スペース) を探して、データ長を判定するようなケース
/
POS = INDEX(REC_BUFFER, ‘,’);
IF POS > 0 THEN DO;
/ カンマが見つかった後の処理 /
END;
/
- 2. VERIFYの活用: 数値項目に不正な文字が含まれていないかチェック
- ‘0’から’9’以外の文字が含まれていれば、その位置を返す
/
POS = VERIFY(REC_BUFFER, ‘0123456789’);
IF POS > 0 THEN DO;
/ 不正な文字が見つかった場合のONユニット呼び出しやエラーログ出力 /
PUT SKIP LIST(‘Invalid character found at position: ‘ || POS);
END;
—
3. 「空文字列」と「NULL」の魔窟
現場で最も恐ろしいのは、スキャン対象が空(長さ0のVAR属性文字列)だったり、予期せぬ値が入っていたりする場合だ。
戻り値の挙動
- INDEX(S, P): SまたはPが空文字列の場合、結果は必ず「0」だ。
- VERIFY(S, P): Sが空文字列なら、結果は「0」。Pが空文字列の場合、Sが空でなければ「1」を返す(最初の文字がPに含まれていないと判定されるため)。
特にマイグレーション案件で、「以前のシステムでは動いていたのに、新環境で結果が0になる」というバグが出た場合、大抵は空文字の入力チェック漏れだ。
例外発生のトリガー
PL/Iでは組み込み関数に異常な引数を渡しても、直ちに異常終了するわけではない。しかし、`SUBSTR(S, INDEX(S, P))` のように組み合わせて使う際、`INDEX`が0を返すと、`SUBSTR`の第2引数が0になり、ERROR条件(ON ERROR)が発火する可能性がある。
/i
/ 安全なコーディングの実装例 /
POS = INDEX(REC_BUFFER, ‘,’);
IF POS > 0 THEN DO;
/ ここで初めてSUBSTRを安全に呼び出す /
CALL PROCESS_DATA(SUBSTR(REC_BUFFER, 1, POS – 1));
END;
ELSE DO;
/ 見つからなかった場合のデフォルト制御 /
END;
—
最後に:ベテランからの助言
PL/Iは古臭い言語だと言われることもあるが、その仕様は非常に計算され尽くしている。`INDEX`と`VERIFY`を適切に使い分けるだけで、コード行数は劇的に減り、可読性は上がる。
もし君が今、レガシーバッチの改修を行っているなら、まずは`ON ERROR`ブロックを一つ仕込んでみてほしい。どこで、どんな引数が渡されて落ちているのか、それを見るだけでデバッグ時間は半分になる。
コードは「書く」ものではなく「読み継ぐ」ものだ。後輩が君のコードを見たときに、「なるほど、ここはVERIFYで妥当性検証をしているのか」と一瞬で理解できる。そんなプロフェッショナルな記述を心がけてくれ。
何か壁にぶつかったら、また聞きに来い。IBMのメインフレームは、正直なコードには必ず応えてくれるからな。
