IBM i 7.4 TR4で、新たな3つのRPG組み込み関数が発表されました。これらの関数の機能およびその提供意図について、ジョン・パリス氏が例題を含めて解説しています。(編集部)
ジョン・パリスがIBM i 7.4 TR4の発表内容から3つの新しいRPGの組み込み関数 %Upper、%Lower、%Splitについて解説します。
06/03/2021 ジョン・パリス
IBM i 7.4のTR4と同じ発表の中で、3つの新しいRPG組み込み関数(BIF) – %Upper、%Lower、%Split - が導入されました。それらが何を提供してくれるのかを見てみましょう。
%Upperと%Lower
これらのBIFの目的は、その名前からしてとても明白で、これらはまさに期待する通りの働きをします。すなわち、これらのBIFは入力文字列を受け取り、それを大文字(または小文字)の列に変換します。
一見したところ、これらの新しい機能はちょっと拍子抜けの様に見えます。何だかんだ言っても、何年もの間自分達自身でこれらの機能を(通常%XLATEまたはSQLの大文字/小文字機能を使って)コーディングしてきました。ですから、RPGにこれらのBIFが加わって何がそんなに嬉しいのでしょう?
それには2つの理由があります。第1に、最近私は新しいRPGプログラマーの訓練に多くの時間を費やしてきました。これらの訓練生たちは、通常他の言語の経験があり、そのような機能が利用可能だという事を期待しています。RPGにこの機能が無いというのは「汚点」でした。第2に、IBM iのユーザーの間で、英語以外の言語で、とりわけ名前や住所のようなテキストを扱える機能の必要性に対する関心が高まっています。多くの場合、これらの言語にはアクセント記号付き文字が含まれています。このことをプログラマーが十分に理解しておらず、それらの文字を手作りの「ソリューション」では受け付けないケースを数多く見てきました。今や、彼らは要求される可能性のある文字ごとに手作業で考慮することなしに、そのようなデータを取り扱う単純で首尾一貫したアプローチを手にしたのです。
下の表は、これらのBIFを使って英語のテキストを処理した結果とフランス語を処理した結果を示しています。
オリジナルの文 | %Upper | %Lower |
---|---|---|
This is a mixed case string. | THIS IS A MIXED STRING. | this is a mixed case string. |
C’est une chaîne de cas mixte. | C’EST UNE CHAÎNE DE CAS MIXTE. | c’est une chaîne de cas mixte. |
これらのBIFの両方に、オプションの第2、第3パラメータがあります。第2パラメータはテキスト内の変換を開始する位置を示します。デフォルトは先頭です。第3パラメータは変換される文字数を表します。デフォルトは文字列の終わりまでです。ですから、例えば入力文字列内の最初の文字以外のすべての文字を小文字に変換したければ、%Lower( inputString : 2 )の様にコーディングすることになります。同様に、入力文字列の最初の1文字だけを大文字に変換したければ、%Upper( inputString : 1 : 1 )とコーディングできます。後ほどこの例を示します。
%Split
このBIFの持ち味は遥かに明白です。この関数は文字列を入力し、それを個々の要素に分割します。デフォルトのセパレーター文字は空白文字ですが、数ある文字の中からプログラマーが指定した任意の1文字をセパレーター文字にすることができます。結果は一時配列に入れられ、For-Eachループで直接処理するか、正規の配列に代入することができます。
単純な文をその構成語に分割するのにこの関数を使う簡単な例から始めましょう。%Splitは可変長配列を返すので、その結果を処理するのに単純なFor-Eachループを使うことができます。For-Eachループに馴染みが無い場合、その詳細に関しては私たちのブログをお読みください。
Dcl-S input1 VarChar(50) Inz( 'Words and still more words'); Dcl-S field VarChar(15); dsply input1; For-each field in %Split(input1); // デフォルトにより空白文字で分割 dsply field; Endfor; 次に、私と同様に以下の例の様にこの関数CSV文字列を分割するのに使いたいと思うかも知れません Dcl-S input2 VarChar(50) Inz( 'Field1,Field2,"Third field",Last'); dsply input2; For-each field in %Split(input2: ','); // コンマセパレーター dsply field; Endfor; |
セパレーター文字が空白文字の場合、それはまさしく私たちが望むものです。しかし、CSVを扱っている場合、省略された値またはヌル値のせいでセパレーター文字が連続するのは普通のことです。例えば、上記の例でField2に値がないとすると、input2は’Field1,,”Third field”,Last’のようになると予想されます。その入力を%Splitで処理した場合、3つの要素だけが返され、結果的に”Field”という値をあたかも第2フィールドであるかのように処理してしまう危険性があります。
これに対処する1つの方法は、2つの連続する区切り文字が絶対にないことを保証するために、%Splitで処理する前に入力文字列を修正することです。以下のコードはこれを行うための1つの方法です(コードの後で説明をします)。
Dcl-S string1 VarChar(50) inz('Field1,,"Third field",Last'); Dcl-S string2 VarChar(50); Dcl-S names VarChar(20) Dim(*auto: 20); Dcl-S name VarChar(20); string2 = %SCANRPL (',' : '@,@' : string); // 注1 dsply string1; dsply string2; // Field1@,@@,@"Third field"@,@Lastを表示 names = %Split (string2 : ','); // 注2 For-each name in names; dsply name; // Field1@ - @@ - @"Third field"@ - @Lastを表示 names = %Trim(names : '@'); // すべてから先頭及び後続の@を削除 For-each name in names; dsply name; // Field1 - - "Third field" – Lastを表示 Endfor; |
注1:%ScanRplを使いすべてのカンマ記号を’@,@’という文字列に置き換えます。@記号は単なる提案であり、入力文字列中に出現しないと分かっている文字であればどんな文字でも構いません。
注2:次にフィールドを分割するために%Splitを使います。この例では後続の処理のために%Splitの結果を動的配列に代入していることに注意してください。伝統的な配列を使うこともできた(そして事実7.4より前のリリースではそうする必要がある)のですが、%Splitの結果は一時的な可変次元配列なので、動的配列の使用がぴったりしている様に思えます。また、そうすることで配列に対して単純にFor-Each処理を適用でき、プログラムロジックを簡単にできます。
このコードをコンパイルして実行すると、表示装置には明らかに結果データの中に偽の@記号が表示されます。幸運にも%Trim関数を使うことでこれらの文字を大変容易に取り除くことができ、そのBIFはすべての配列に単純に適用できます。
これが、読者の皆さんが出会うであろうすべてのCSV形式の文字列に対する完全な解決策を提供するわけではありません。例えば、CPYFMIMPFコマンド(“身震い”)、Open Accessハンドラ、スコット・クレメント氏のCSVユーティリティ(www.scottklement.com/csv/)に頼らざるを得ない場合も依然としてあります。しかし、多くの場合このやり方でうまく行くでしょう。
BIFを結び付ける
ここで説明した3つのBIFを結び付けて、名前の各部分の最初の文字を大文字にする簡単なプログラムを遊び半分で書きました。要するに、このプログラムは名前全体を個々の要素に分割し、各要素を小文字に変換した後、各々の結果の文字列の最初の1文字を大文字にします。それから、その結果を一続きの文字列につなぎ合わせ、改訂された名前にします。コードは以下のとおりです。
dcl-s inputName char(50) inz('WILLIAM james williams'); dcl-s outputName varchar(50) inz; dcl-s names varchar(20) dim(*auto: 100); dcl-s name varchar(20); dcl-c blank ' '; names = %split( inputName ); for-each name in names; outputName += %Upper( %Lower( name ) : 1 : 1 ) + blank; endfor; // outputName にはWilliam James Williams が含まれている |
想像できるように、これらの新しいBIFを使うともっと多くのことができます。それらのどんな使い方を皆さんが見つけたかを教えて貰いたいと思います。
最後の詳細とRDi注釈
これらのBIFはIBM i 7.3と7.4の両リリースで利用可能で、コンパイラーと実行時サポートの両方に対するPTFが必要です。必要な現行PTF番号の完全な詳細はRPG Cafeで見つけられます。
最後に我らが仲間であるRDi信者に一言。近年私達は甘やかされてきており、新しい機能に対するRDiサポートは、しばしば機能そのものが利用可能になる前に提供されてきました。残念ながら今回はそうでなく、RDiは次のリリースまでこの新しいBIFを認識しないでしょう。