秋の訪れとともにやって来たRPGの新機能(併せて春の新機能も)
この記事を書き始めたときに中心テーマとして考えていたのは、最新の9月のテクノロジー リフレッシュ(TR)とともに追加されたRPGの新機能を紹介することでした。ところが、今年の春に追加されていた1つの機能強化について参照しようとしたところ、春の機能強化については、私の記事でまったく取り上げていなかったことにふと気付かされました。
うっかりしていました。結果として、今回の「記事」では、4月の発表と9月の発表の両方で、つまりは今年追加されたすべてのRPGの機能強化をカバーすることとなります。前後半の2回に分けてそれらについて紹介する予定です。前半となるこの記事では、配列に関する機能について取り上げます。
RPGの配列処理オプションの利用範囲は、ここ何年かで大幅に広がっています。ただし、私たちのほとんどは、それらをあまり十分に活用しているとは言えないようです。そして、後半となる次回の記事では、今年の機能強化のうちのその他の新機能、たとえば、他の新たなBIFや、RPGデバッグ機能へ追加された有用な新機能などについて取り上げる予定です。
配列の機能強化
まずは、春の追加機能である、%SPLITについて見てみましょう。一見したところでは、どうして%SPLITが配列関数に含められるのか疑問に思われるかもしれません。そうみなしたのは、 %SPLITはテキスト入力から配列を生成するからです。たとえば、変数 textString に簡単な文が格納されていて、その文を個々の単語に分解したい場合は、次のようにコーディングすることができます。
dcl-s textString varchar(50)
inz('The quick brown fox jumps over the lazy dog');
dcl-s words varchar(20) dim(*Auto: 20);
words = %Split( textString );
このBIFは、デフォルトの区切り記号であるスペースを使用して、入力をサブストリングに「分割」します。 結果として、配列 words の要素1には「The」、要素2には「quick」が格納されます(要素3以降も同様)。
必要な処理が、CSVストリングを分解することである場合も、%SPLITを使用してそうした処理を行うことができます。この場合は、複数の区切り文字を含めることができる、オプションの2つ目のパラメーターを使用して行います。次のようにします。
words = %Split( csvString: ',' ); // Just split at commas
words = %Split( textString: '.,!? ' ); // Split on any major punctuation
1つ、注意点があります。%SPLITは、連続する区切り記号を無視します。ほとんどの場合、これは便利なことですが、状況によっては問題が生じることもあります。たとえば、CPYFRMIMPFを使用して、「 ABC,,XYZ 」というストリングが含まれているCSVファイルを処理する場合、結果として、 「ABC」、ブランク、 「XYZ」という3つのフィールドになります。しかし、%SPLITが生成するのは、2つの配列要素のみです。2つ目のコンマは無視されるからです。そのため、こうした状況では、何らかの入力の前処理が必要となる場合もあります。
2つ目の例は、文を分解する際に、ほとんどの句読点記号が無視されるようにする方法を示しています。スペースが区切り記号とみなされるように、ストリングの最後にブランクを含めたことに注目してください。また、引用符なども無視されるようにしたい場合は、区切り記号のリストにそれらの記号を追加するだけです。
ここで取り上げているのはBIFであるため、同じタイプの変数が使用できるところであれば、どこでも使用できることを忘れてはなりません。したがって、たとえば、プログラム内で配列を定義しなければならないわけではなく、単純に%SPLITをFOR-EACH命令コードの引数として使用することもできます。
for-each word in %Split( textString );
// Process the word ...
EndFor;
%MINARRと%MAXARR
%MINと%MAXが初めて導入されたとき、嬉しかったことを憶えていますが、その時に併せて思ったことは、値のリストではなく配列を処理するバージョンもあったらなあ、ということでした。問題だったのは、これらの元のバージョンのBIFが返すのは実際の値であり、配列を処理する際に本当に返してもらいたいのは、その値の指標だということでした。これらのBIFにあまり馴染みがない場合は、 こちら のIBMドキュメントで基本情報を参照することができます。
そうした隙間を埋めるのが、%MINARRと%MAXARRです。%MINARRは、配列内の最小値の指標を返し、%MAXARRは最大値の指標を返します。これらのBIFは、従来の配列またはDS配列に適用することができます。
この後者の機能は特に有用です。たとえば、DS配列に、販売員番号と売上高が格納されているとします。売上高が最も少ない販売員を確認する場合は、売上高の値に%MINARRを適用し、結果の指標を使用して販売員の番号と名前にアクセすることができます。たとえば、次のようにします。
dcl-ds salesData qualified dim(*Auto : 100); // Maximum 100 salesmen
salesRep# char(5);
name varchar(30);
salesToDate packed(9:2);
end-ds;
index = %minArr( salesData(*).salesToDate );
Dsply ( 'Rep #' + salesData(index).salesRep# + ' Name: '
+ salesData(index).name );
3つ目のパラメーターを使用して、検索する最大要素数を指定することで、検索の範囲を制限することができます。 デフォルトでは、配列全体が検索範囲となります。 これらの例で示されているように、最近では、ほとんどの作業で自動配列を使用しているため、BIFの範囲の制限について気にすることはなくなっています。RPGが自動的に処理してくれるからです(動的配列にあまり馴染みがない場合、詳細については こちらの記事を参照してください)。まだV7.4にアップデートしていない場合は 、検索の範囲を制限する方法は、この3つ目のパラメーターを使用して、検索する最大要素数を指定する方法のみになります。
次の例では、変数 activeItems には、配列 invoiceList の実際の要素数が格納されており、最も高い値のインボイスを見つけようとしています。
2つ目のパラメーターについて、どのようなものなのか疑問に思われるかもしれません。このパラメーターは、検索の開始点となる指標を指定するのに使用することができます(必要な場合)。ご想像の通り、指定されるパラメーターが1つのみの場合は、デフォルトで、1の値になります。
index = %maxArr( invoiceList(*).invoiceTotal : 1 : activeItems );
SORTAの機能強化
しばらく前に、SORTAは、DS配列のソートが可能となるように機能強化されました。この機能は有用ですが、1つのキー フィールドでのソートに制限されていました。つまり、複数キー ソートが必要となったときは、それまでと同様に、C関数のqsort()を援用する必要があったということです。長年、使用してきたので、私にとっては問題ないのですが、私の後任としてコードの保守を担当する人にとっては障害となりかねません。新たなサポートにより、RPGが直接、複数キー ソート機能をサポートするようになったため、qsort()の援用が必要となるケースは非常に少なくなることでしょう。
このサポートは、%FIELDSを使用して、優先順位に従って使用されるキー フィールドをリストすることによって提供されます。以下の例では、動物のリストを種別(猫、犬、など)ごとに体重でソートしています。たとえば、すべての猫がまとめられ、体重順に並べられます。
dcl-ds myAnimals qualified dim(99);
ID int(10);
type varchar(16);
name varchar(16);
weight packed(7:2);
end-ds;
...
SortA myAnimals %Fields( type: weight );
終わりに
ご覧の通り、この記事では、プログラミング作業を少し行いやすくする、いくつかの素晴らしい機能について見てきました。RPGは成長し続けています。
これらの新機能をすぐに試してみたいという方は、そうする前に、必要とされているPTFをインストールしてあるか必ずご確認ください。春のTRと秋のTRの両方の詳細については、こちら( https://ibm.biz/rpg_cafe)で参照することができます。
後半となる次回の記事では、今年、RPGに追加されたその他の機能について紹介する予定です。