1

RPG のもう 1 つのことは、文字列操作関数/プロシージャを記述することです。

ほとんどの場合、RPG の文字列は (少なくとも私たちのプログラムでは) 固定長であり、おそらくもっと重要なのは、文字列が常に有限の長さであるため、一般的な文字列操作の手順を書きたいときは、いつも迷ってしまうことです。

任意の長さの文字列を処理するプロシージャを作成するにはどうすればよいですか? 関数スタイル (のようにtext = manip_str(text);) を実行すると、問題はありますか? 引数を直接(のようにmanip_str(text);)操作している場合、さまざまな長さでまったく機能しますか?

私自身の試みを回答として投稿しますが、よくわからない問題がいくつかあります。多くの人がそのようなタスクを1回または1000回経験したと確信しているので、どうしますか。さまざまなアプローチを歓迎しますが、それらのアプローチの問題点について言及するのが最善です。

質問する前に: (EBCDIC) バイト文字列と (UTF-16) Unicode 文字列に関して、この問題があります。しかし、私は手順を2回、それぞれ1回ずつ受けても大丈夫です。

4

2 に答える 2

3

RPG のほとんどの文字変数は実際には固定長です。これは、有限の長さを意味します。50a として定義された文字には、常に正確に 50 文字が含まれます。Eval myChar = 'A'; は、50 文字 (文字 A の後に 49 個の空白が続く) を含む myChar になります。これは退屈ですが重要です。

つまらないが重要な 2 番目のビットは、呼び出し先ではなく、呼び出し元がメモリを割り当てることを理解することです。呼び出し元が myChar 50a を宣言し、呼び出し先が myParm 65535a を宣言した場合、呼び出し元は 50 バイトのストレージのみを初期化しています。呼び出し先が 50 バイトを超えて myParm を操作しようとすると、状態が不明なストレージを操作しています。彼らが言うように、予測できない結果が生じる可能性があります。

これは、サイズが事前にサブプロシージャーに知られていない文字変数を処理するサブプロシージャーに関する質問の背景です。これを処理する古典的な方法は、文字変数だけでなく、その長さも渡すことです。eval myProcedure(myChar: %len(myChar)); これはちょっと見栄えが悪く、すべての呼び出し元が myChar の長さを計算する必要があります。サブプロシージャーが着信パラメーターに問い合わせて、呼び出し元がどのように定義したかを調べることができれば、それは確かに素晴らしいことです。

IBM は、運用記述子と呼ばれるものを通じて、まさにそのような機能を提供しています。操作記述子を使用して、呼び出し元は文字パラメーターに関するメタデータを呼び出し先に渡します。CEEDOD APIを介してそれを取得します。ここに CEEDOD の使用例があります。

基本的に、サブプロシージャーは、操作記述子が必要であることを宣言する必要があります。

 dddeCheck         pr              n   opdesc
 d test                          20a   const options(*varsize)

呼び出し元は、サブプロシージャーに対して通常の呼び出しを行います。

if ddeCheck(mtel) = *on;               // 10 bytes
...
endif;
if ddeCheck(mdate: *on) = *on;         // 6 bytes
...
endif;

呼び出し元は、異なるサイズの固定長変数をサブプロシージャーに渡すことに注意してください。

サブプロシージャーは、CEEDOD を使用して着信パラメーターの長さを調べる必要があります。

     dddeCheck         pi              n   opdesc
     d test                          20a   const options(*varsize)
...
     dCEEDOD           pr
     d parmNum                       10i 0 const
     d descType                      10i 0
     d dataType                      10i 0
     d descInfo1                     10i 0
     d descInfo2                     10i 0
     d parmLen                       10i 0
     d ec                            12a   options(*omit)

     d parmNum         s             10i 0
     d descType        s             10i 0
     d dataType        s             10i 0
     d descInfo1       s             10i 0
     d descInfo2       s             10i 0
     d parmLen         s             10i 0
     d ec              s             12a
...
       CEEDOD (1: descType: dataType: descinfo1: descinfo2: parmlen: *omit);

この時点で、parmlen には、呼び出し元が着信変数を定義した長さが含まれています。今、その情報を使って何かをするのは私たち次第です。文字ごとに処理している場合は、次のようにする必要があります。

for i = 1 to parmLen;
  char_test = %subst(test: i: 1);
  ...
endfor;

単一の文字列として処理している場合は、次のようにする必要があります。

returnVar = %xlate(str_lc_letters_c: str_uc_letters_c: %subst(s: 1: parmLen));

重要なことは、その参照が呼び出し元によって定義された実際の変数の長さによって何らかの形で制限されない限り、決して入力パラメーターを参照しないことです。これらの注意事項は、固定長変数にのみ必要です。コンパイラは、可変長文字変数の長さを既に認識しています。

コンパイラが CONST を介して myFixed を myVarying にマップする方法について、その仕組みを理解してください。コンパイラは、myFixed から MyVarying にすべてのバイトをコピーします。myFixed が 10a の場合、myVarying は 10 バイトの長さになります。myFixed が 50a の場合、myVarying は 50 バイトの長さになります。末尾の空白はすべての固定長文字変数の一部であるため、常に含まれます。これらの空白は、空白を無視する変換手順ではそれほど重要ではありませんが、文字列を中央揃えにする手順では重要になる場合があります。この場合、操作記述子に頼るか、次のようなことをする必要がありますupperVary = str_us(%trimr(myFixed));

于 2013-03-06T18:48:13.917 に答える
0

私が見つけた RPG で文字列を渡す最も柔軟な方法は、64k-varlength 文字列で動作し、次のように渡します*varsize(実際には、渡された文字列のバイト数のみを送信することになっているため、64k は問題にならないはずです – 私が見つけたと思いますスコット・クレメントによってどこかで示唆された)。ここで、それを使用してAZのみのupcase関数を作成する方法を示します(最も基本的な例であるため):

 * typedefs:
Dstr_string_t     S          65535A   VARYING TEMPLATE

 * constants:
Dstr_uc_letters_c C                   'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
Dstr_lc_letters_c C                   'abcdefghijklmnopqrstuvwxyz'

 * prototype:
Dstr_uc           PR                  like(str_string_t)       
D s                                   like(str_string_t)       
D                                       options(*varsize) const

 * implementation:
Pstr_uc           B                   export                   
D                 PI                  like(str_string_t)       
D s                                   like(str_string_t)       
D                                       options(*varsize) const
 /free                                                         
  return %xlate(str_lc_letters_c:str_uc_letters_c:s);          
 /end-free                                                     
Pstr_uc           E 

ここで私に関係することが複数あります。

  • これに渡す固定長文字列に問題がある可能性はありますか?
  • この「必要なだけのバイト数だけが渡される」ことは、戻り値に対しても機能しますか? 3文字の文字列を大文字にするたびに、何千バイトも予約して渡すのは嫌です。
  • 64k バイトまでしか柔軟に対応できません。しかし、それはより理論的には私たちのプログラムの問題だと思います – 少なくとも今のところ...
于 2013-03-06T16:57:49.377 に答える