【PL/I超入門】怪しい文字、見つけちゃいました!VERIFY関数で入力チェックをスマートに!
皆さん、こんにちは!メインフレームの世界へようこそ!JavaやCOBOLの経験はあるけど、「PL/I?なにそれ美味しいの?」なんて思っているあなた、大丈夫!このブログでは、PL/Iのちょっと変わった世界を、優しく、そして時に面白く紐解いていきます。今日は、特に「怪しい文字」を見つけるのに大活躍する「VERIFY関数」に焦点を当てて、その秘密に迫りますよ!
PL/Iプログラムの「おうち」ってどんな感じ?
まず、PL/Iプログラムがどんな構造になっているのか、イメージを掴んでおきましょう。他の言語でいうところの「クラス」や「メソッド」、「メイン関数」にあたるものが、PL/Iでは主に `PACKAGE` や `PROCEDURE` といったキーワードで表現されます。
- `PACKAGE`: これは、関連する `PROCEDURE`(処理のまとまり)やデータなどを、ひとつの「箱」にまとめて管理するための仕組みです。プログラムの設計図みたいなものですね。
- `PROCEDURE`: こちらが、実際の処理を行う「手続き」の単位です。他の言語でいう「関数」や「メソッド」に一番近いイメージです。
- `OPTIONS(MAIN)`: そして、プログラムの「入り口」となる `PROCEDURE` には、必ず `OPTIONS(MAIN)` というおまじないをつけます。これがついている `PROCEDURE` が、プログラムの実行開始点になるんです。
ちょっと不思議に聞こえるかもしれませんが、これはプログラムを整理して、どこからどこまでが何をする部分なのかを明確にするための、PL/Iなりの「こだわり」なんですよ。
例えば、こんな風に書きます。
/ これがPL/Iプログラムの基本形 /
MY_PROGRAM: PROCEDURE OPTIONS(MAIN);
/ ここにメインフレームで動く処理を書く /
DECLARE / 変数の宣言とか / … ;
/ 処理本体 /
PUT SKIP LIST(‘Hello, PL/I World!’);
END MY_PROGRAM;
`MY_PROGRAM:` の部分が、この `PROCEDURE` の名前ですね。`OPTIONS(MAIN)` が、この `PROCEDURE` がプログラムの開始点であることを示しています。`DECLARE` は、後で出てくる「変数」の宣言をする場所です。そして、`PUT SKIP LIST(…)` は、画面に文字を表示するための命令。お決まりの「Hello, World!」ですね!
「怪しい文字」って、一体何者? ~VERIFY関数のご紹介~
さて、今日の主役、`VERIFY` 関数です!これは、ある文字列の中に、指定した「許可された文字のセット」に含まれない文字が一つでもあるかどうかをチェックしてくれる、とっても便利な関数なんです。
例えるなら、
「この郵便番号、数字とハイフン以外は入っちゃダメ!」
「この名前、ひらがなとカタカナと漢字だけにしてほしいんだけど…」
みたいな、入力データの「お約束」を守らせるのにピッタリなんです。
`VERIFY` 関数は、二つの引数を取ります。
1. チェックしたい文字列: まず、どんな文字列をチェックしたいのかを指定します。
2. 許可された文字のセット: 次に、その文字列に含まれていても良い文字の「リスト」を指定します。
そして、この関数が返す値は、
- 0: チェックしたい文字列の全ての文字が、許可された文字のセットに含まれている場合。
- 0より大きい値: チェックしたい文字列の中で、最初に見つかった「許可されていない文字」の、文字列内での位置(1から始まるインデックス)。
つまり、返り値が `0` なら「OK!全部許可された文字だね!」、`0` より大きかったら「あれ?ここで許可されていない文字が見つかったよ!」ということになるんです。
入力チェックルーチンでVERIFY関数を大活用!
では、この `VERIFY` 関数を、実際のプログラムでどう使うのか見てみましょう。例えば、ユーザーからの入力データが、期待通りの形式になっているかチェックする場面を想像してみてください。
例:郵便番号チェック
「郵便番号は、数字7桁で、3桁目と4桁目の間にハイフンが入っている」というルールがあるとしましょう。
/ 郵便番号チェックルーチン /
CHECK_POSTAL_CODE: PROCEDURE(INPUT_POSTAL, RESULT_CODE);
/
- INPUT_POSTAL: チェックする郵便番号文字列 (例: ‘123-4567’)
- RESULT_CODE: チェック結果を返す変数 (0: OK, 1: NG)
/
DECLARE INPUT_POSTAL CHAR(9) VARYING; / 9文字まで可変長の文字列 /
DECLARE RESULT_CODE FIXED BINARY; / 結果コード (整数) /
DECLARE HYPHEN_POS FIXED BINARY; / ハイフンの位置 /
DECLARE NUMERIC_CHARS CHAR(10) CONSTANT INITIAL(‘0123456789’); / 数字のセット /
DECLARE ALLOWED_CHARS CHAR(11) CONSTANT INITIAL(‘0123456789-‘); / 数字とハイフンのセット /
RESULT_CODE = 0; / まずはOKと仮定 /
/ 1. 全体の文字チェック: 数字とハイフン以外がないか? /
IF VERIFY(INPUT_POSTAL, ALLOWED_CHARS) > 0 THEN
DO; / 許可されていない文字が見つかった! /
RESULT_CODE = 1; / NGとする /
RETURN; / ここで処理を終える /
END;
END;
/ 2. ハイフンの位置チェック: ちゃんと3桁目の次にあるか? /
HYPHEN_POS = INDEX(INPUT_POSTAL, ‘-‘); / INDEX関数でハイフンの位置を探す /
IF HYPHEN_POS ^= 4 THEN / 4文字目(3桁目の次)にハイフンがない場合 /
DO;
RESULT_CODE = 1; / NGとする /
RETURN;
END;
END;
/ 3. 文字数チェック: 正しい文字数か? (例: ‘123-4567’なら8文字) /
IF LENGTH(INPUT_POSTAL) ^= 8 THEN / 8文字でない場合 /
DO;
RESULT_CODE = 1; / NGとする /
RETURN;
END;
END;
/ ここまで来たら、全てのチェックをクリア! /
/ RESULT_CODE は 0 のまま /
END CHECK_POSTAL_CODE;
コード例のポイント解説
- `DECLARE … VARYING`: `VARYING` は、文字列の長さを可変にできる属性です。郵便番号のように、入力によって長さが変わる可能性がある場合に便利ですよね。
- `DECLARE … CONSTANT`: `CONSTANT` は、一度値を設定したら、もう変更できない「定数」にするための属性です。`NUMERIC_CHARS` や `ALLOWED_CHARS` のように、固定の文字セットを指定するのに役立ちます。
- `VERIFY(INPUT_POSTAL, ALLOWED_CHARS)`: ここが `VERIFY` 関数の出番です!`INPUT_POSTAL` の中に、`ALLOWED_CHARS`(数字とハイフン)に含まれない文字があれば、その文字の位置が返ってきます。もし一つもなければ `0` が返ります。
- `INDEX(INPUT_POSTAL, ‘-‘)`: `INDEX` 関数は、指定した文字列 (`INPUT_POSTAL`) の中に、別の文字列 (`’-‘`) が最初に現れる位置を返します。これでハイフンの位置を特定しています。
- `IF HYPHEN_POS ^= 4 THEN …`: `^=` は「等しくない」という意味の比較演算子です。ハイフンの位置が `4`(4文字目)でなければ、NGと判断します。
- `RETURN`: `RETURN` は、その `PROCEDURE` の実行をそこで終了させ、呼び出し元に戻る命令です。
この例では、まず `VERIFY` 関数で「数字とハイフン以外の余計な文字が入っていないか」をざっくりチェックし、その後で `INDEX` 関数や `LENGTH` 関数を使って、より詳細なルール(ハイフンの位置や文字数)をチェックしています。このように、`VERIFY` 関数は、入力チェックの「最初の関門」として、非常に効果的に使えるんです。
PL/Iの「ちょっと変わった」データ属性にも慣れちゃおう!
PL/Iには、`CHAR(n) VARYING` の他にも、ちょっとユニークなデータ属性があります。例えば、
- `PIC`句: COBOLでお馴染みの `PIC` 句もPL/Iで使えます。数値の桁数や小数点以下の位置、符号などを細かく定義できます。
DECLARE PRICE PIC ‘9999.99’; / 例: 1234.56 のような数値を格納 /
- `BASED`: メモリ上の特定の場所を指し示すポインタのような概念です。これは少し高度ですが、データ構造を柔軟に扱いたい時に強力な武器になります。
最初は「なんだこれ?」と思うかもしれませんが、一つずつ、これらの属性がどんな役割を持っているのかを理解していくと、PL/Iのコードが「読める」ようになってきます。そして、なぜそのような書き方になっているのか、その背景にある設計思想が見えてくると、レガシーシステムも怖くなくなってきますよ!
まとめ
今日は、PL/Iの `VERIFY` 関数を使った入力チェックの基本と、プログラムの基本構造について見てきました。
- `PACKAGE` や `PROCEDURE OPTIONS(MAIN)` でプログラムの骨組みを作る。
- `VERIFY` 関数は、許可されていない文字を効率的に検出してくれる!
- `VERIFY` 関数を入口にして、他の関数と組み合わせることで、より厳密な入力チェックが可能になる。
どうでしたか?PL/Iの世界、少しは身近に感じられましたでしょうか?
「この関数、どう使うんだろう?」「このデータ宣言、意味が分からない…」
そんな疑問が出てきたら、ぜひまたこのブログに戻ってきてくださいね。皆さんのPL/I学習の旅を、これからも全力でサポートしていきます!
