1

たとえば、長さが可変の csv レコードがあります。

0005464560,45667759,ZAMTR,!ACC 12345678,DR,79.85 へ

0006786565,34567899,ZAMTR,!ACC 26575443,DR,1000 へ

これらの各フィールドを分離する必要があり、最後のフィールドはお金でなければなりません。

しかし、ファイルを読み取り、レコードをフィールドに紐付けを解除すると、最後のフィールドの末尾にジャンク値が含まれていることがわかりました。amount(money)欄は、先頭5桁、ドット1桁、末尾2桁の8文字である必要があります。入力からの値は、 13.5 、 1000 、 354.23 などの任意の値にすることができます。

    "FILE SECTION"

        FD INPUT_FILE.
            01 INPUT_REC                                   PIC X(66).

    "WORKING STORAGE SECTion"

            01 WS_INPUT_REC                                 PIC X(66).

            01 WS_AMOUNT_NUM                                PIC 9(5).9(2).
            01 WS_AMOUNT_TXT                                PIC X(8).

"MAIN SECTION"

                        UNSTRING INPUT_REC DELIMITED BY ","
                        INTO WS_ID_1, WS_ID_2, WS_CODE, WS_DESCRIPTION, WS_FLAG, WS_AMOUNT_TXT

                        MOVE WS_AMOUNT_TXT(1:8) TO WS_AMOUNT_NUM(1:8)

                        DISPLAY WS_AMOUNT_NUM

表示から、値はかなり正常です: 345.23, 1000, しかし、フィールドをファイルに書き込んだ後、次のようになります:

79.85^M^@^@ 137.35^M^@

フィールド WS_AMOUNT_TXT から取得したフィールド WS_AMOUNT_NUM を調べたところ、^@ は一種の LOW-VALUE であることがわかりました。ただし、^M が何かを見つけることができません。これはスペースではなく、高値でもありません。

4

2 に答える 2

4

私は推測していますが、可変長レコードをファイルから固定長 COBOL レコードに読み込んでいるようです。COBOL レコードの末尾のがらくたは、あなたに悲しみを与えています。そのジャンクが読み取りごとにどの程度一貫しているかを言うのは難しいです (実際の入力レコード長の境界を超えるデータは技術的に定義されていません)。そのジャンクはWS_AMOUNT_TXTUNSTRING

この問題を解決するには、いくつかの方法があります。ここで提示する提案は最適ではないかもしれませんが、単純であり、仕事を成し遂げるはずです。

ステートメントの最後のINTOフィールドはWS_AMOUNT_TXTUNSTRING末尾のジャンクをすべて受け取るフィールドです。そのがらくたは取り除く必要があります。最後のフィールドで有効な文字は数字と小数点のみであるため、次のようにクリーンアップできます。

PERFORM VARYING WS_I FROM LENGTH OF WS_AMOUNT_TXT BY -1
          UNTIL WS_I = ZERO
    IF WS_AMOUNT_TXT(WS_I:1) IS NUMERIC OR
       WS_AMOUNT_TXT(WS_I:1) = '.'
       MOVE ZERO TO WS_I
    ELSE
       MOVE SPACE TO WS_AMOUNT_TXT(WS_I:1)
    END-IF
END-PERFORM

上記のコードの基本的な考え方は、最後のUNSTRING出力フィールドの末尾から先頭までスキャンし、有効な数字または小数点ではないものをすべてスペースに置き換えることです。有効な数字/10 進数が見つかったら、残りが有効であると仮定してループを終了します。

クリーンアップ後、前の質問NUMVALに対する私の回答で概説した組み込み関数を使用して 、WS_AMOUNT_TXT を数値データ型に変換します。

最後に、バッファに残っている可能性のある前回の読み取りから残ったデータを吹き飛ばすMOVE SPACES TO INPUT_REC前に、1 つのアドバイスがあります。READこれにより、「長い」レコードの後に​​非常に「短い」レコードを読み取るときに保護されます。そうしないと、前の読み取りから残ったデータにつまずく可能性があります。

お役に立てれば。

編集可変長ファイルの読み取りに関する質問に対するこの回答に気づきました。可変長入力レコードを使用する方が優れた方法です。実際の入力レコード長を指定すると、次のようなことができます。

UNSTRING INPUT_REC(1:REC_LEN) INTO...

fileの後にREC_LEN指定された変数はどこにありますか。あなたが遭遇しているすべてのジャンクは、 で定義されているように、レコードの終了後に発生します。上記のように参照変更を使用すると、個々のデータ フィールドを分離する作業を行う前に、それが削除されます。OCCURS DEPENDING ONINPUT_RECFDREC_LENUNSTRING

EDIT 2: で参照変更を使用することはできませんUNSTRING。くそー...他のいくつかのCOBOL方言では可能ですが、OpenVMS COBOLでは不可能です。次のことを試してください。

MOVE INPUT_REC(1:REC_LEN) TO WS_BUFFER
UNSTRING WS_BUFFER INTO...

最長の入力レコードを保持するのに十分な長さWS_BUFFERのワーキング ストレージ変数はどこにありますか。短い英数字フィールドを長いフィールドにする場合、宛先フィールドは、残りのスペースを埋めるために使用されるスペース (つまり ) で左揃えになりPIC Xます。先頭と末尾のスペースは関数に受け入れられるので、まさに必要なものがあります。MOVEWS_BUFFERNUMVAL

あなたをこの方向に推し進めるのには理由があります。短いレコードを読み取るときに、レコード バッファの末尾にあるジャンクは定義されていません。そのがらくたの一部が数字または小数点になる可能性があります。これが発生した場合、最初に提案したクリーンアップ ルーチンは失敗します。

編集 3: 結果の WS_AMOUNT_TXT には ^@ はありませんが、それでも ^M があります

ファイル システムは、各レコードの末尾にある <CR> (^M のこと) をデータとして扱っているようです。

読んでいるファイルが Windows プラットフォームからのもので、現在は UNIX プラットフォームで読んでいる場合、問題が説明されます。Windows ではレコードは <CR><LF> で終了しますが、UNIX では <LF> のみで終了します。UNIX ファイル システムは、<CR> をレコードの一部であるかのように扱います。

この場合、読み取られたすべてのレコードの最後に単一の <CR> があることはほぼ確実です。これに対処するには、いくつかの方法があります。

方法 1:既に述べたように、COBOL プログラムで処理する前に、Notepad++ またはその他のツールを使用してファイルを事前編集し、<CR> 文字を削除します。個人的には、これが最善の方法だとは思いません。処理ステップが少ないため、COBOL のみのソリューションを使用することを好みます。

方法 2:処理する前に、各入力レコードから最後の文字を削除します。最後の文字は常に <CR> でなければなりません。レコードを可変長として読み取り、実際の入力レコード長を使用できる場合は、次のことを試してください。

SUBTRACT 1 FROM REC_LEN
MOVE INPUT_REC(1:REC_LEN) TO WS_BUFFER
UNSTRING WS_BUFFER INTO...

方法 3:次のように、UNSTRING 時に <CR> を区切り文字として扱います。

UNSTRING INPUT_REC DELIMITED BY "," OR x"0D"
    INTO WS_ID_1, WS_ID_2, WS_CODE, WS_DESCRIPTION, WS_FLAG, WS_AMOUNT_TXT

方法 4:末尾の非数字/非小数点文字をスペースに置き換えて、UNSTRING からの最後の受信フィールドを調整します。この解決策については、この質問の前半で概説しました。オプション (形式 2)INSPECTを使用してステートメントを調べることもできます。REPLACINGこれは、ほとんど同じことを実行できるはずです。すべての x"00" を SPACE に、x"0D" を SPACE に置き換えるだけです。

意志あるところに道あり。上記の解決策のいずれかが機能するはずです。最も使いやすいものを選択してください。

于 2011-07-28T14:58:31.547 に答える
0

^Mはキャリッジリターンです。

Google Refineはこのデータを修正するのに役立ちますか?

于 2011-07-28T08:58:18.310 に答える