2

108 回出現する名前の配列を形成することになっています。左の列に名前 1 ~ 54、右の列に名前 55 ~ 108 があるはずです。1 ページに 108 個の名前が表示されたら、配列を初期化して最初からやり直します。私のコードの出力は、名前1〜54が印刷され、同じページに名前1〜54の横にあるのではなく、右側の列に名前55〜108が表示されていますが、名前1〜54の後にあります。どんな考えでも大歓迎です。

これが私のコードの一部です:

       PERFORM UNTIL ARE-THERE-MORE-RECORDS = 'NO '
           READ NAMELIST-FILE-IN
               AT END
                   MOVE 'NO ' TO ARE-THERE-MORE-RECORDS
               NOT AT END
                   PERFORM 200-PROCESS-ONE-RECORD
           END-READ
       END-PERFORM
       CLOSE NAMELIST-FILE-IN
       CLOSE NAMELIST-FILE-OUT
       STOP RUN.

   200-PROCESS-ONE-RECORD.
       ADD 1 TO NAME-SUB
       MOVE NAME-IN TO NAME-1 (NAME-SUB)
       PERFORM 220-MOVE-RECORDS.


   220-MOVE-RECORDS.
       IF NAME-SUB <= 54
           MOVE NAME-1 (NAME-SUB) TO LEFT-LABEL
           MOVE SPACES TO RIGHT-LABEL
       END-IF
       IF NAME-SUB >= 55
           MOVE NAME-1 (NAME-SUB) TO RIGHT-LABEL
           MOVE SPACES TO LEFT-LABEL
       END-IF
       MOVE DETAIL-LINE TO NAMELIST-RECORD-OUT
       WRITE NAMELIST-RECORD-OUT
           AFTER ADVANCING 1 LINE
       IF NAME-SUB >= 108
           MOVE SPACES TO DETAIL-LINE
           MOVE ZERO TO NAME-SUB
           PERFORM 300-WRITE-HEADING
       END-IF.

情報に対応するために、すべての適切な WORKING-STORAGE エントリをコーディングしました。詳細行の書き方に何か問題があるのか​​ 、それともデータの処理方法に問題があるのか​​ わかりますか?

4

4 に答える 4

3

あなたの論理は間違っています。簡単にするために、216 個の名前があるとします。そのうちの 108 個を読み取り、NAME-1 配列に格納する必要があります。

次に、NAME-1[n] を LEFT-LABEL に、NAME-1[n+54] を RIGHT-LABEL に配置して、54 行をループできます。次に、詳細行を移動して出力に書き込みます。行 n = 1 <= 54 の繰り返し

次の 108 行を読み込んで繰り返します。つまり、2 つのループです。108 人の名前を読み、54 行を出力します。

明らかに、残りを守る必要があります。つまり、108 の倍数の名前がない場合は、次のようになります。

if n <= name-sub 
    move NAME-1[n] to LEFT-LABEL
else
    move spaces to LEFT-LABEL
endif

if n+54 <= name-sub 
    move NAME-1[n+54] to RIGHT-LABEL
else
    move spaces to RIGHT-LABEL
endif

変数を適切に設定する必要があることを認識しています(n + 54は適切なcobolではありません)。大文字と小文字が混在していて申し訳ありませんが、ずっと前にCOBOLを書き、現在は小文字に慣れています。;)

于 2013-02-04T02:00:24.813 に答える
2

すべての IO に対して常にエラー チェックを行う必要があります。

one-file-in-one-file-out は常に次のようになります。

open input
check status
open output
check status
process file until end
close input
check status
close output
check status

process file
read input
check staus
do what is needed
write output
check status

より良いのは次のようなものです:

open input
check status
open output
check status
*priming read*
process file until end
close input
check status
close output
check status

process file
do what is needed
write output
check status
read input
check staus

「プライミング読み取り」は、ファイルの最初のレコード (存在する場合) を処理します。メインロジックを「混乱」させたり、2 つの異なるタイプの「ファイルの終わり」を他の場所で区別したりすることなく、「空のファイル」をきちんと処理できます。「プロセスファイル」の最後にある読み取りは、やや曲がりくねった「AT END/NOT AT END」を取り除きます。

この例では、テーブルに必要な要素は 54 個だけです。ページの「右側」のレコードを処理する場合、「左側」から最初のレコードを取得して、すぐに行を実行できます。

テストにはリテラルではなく 88 を使用します。

ページの最後に「見出し」を付けないでください。処理するレコードがなくなると、見出しの後に「空白のページ」ができてしまいます。

印刷行の書き込みが段落にある場合、その段落を使用して、見出しが必要かどうかを確認できます。初期値は 54 です。

一度に 1 ページずつ印刷する 108 要素のアプローチでは、上部に見出しを作成します。

データが他の値に設定される前に使用されていない場合は、初期値に設定する必要はありません。

あなたは手続きコードに「最小限のピリオド/ピリオド」アプローチを採用しました。

   PERFORM 220-MOVE-RECORDS.

になる

   PERFORM 220-MOVE-RECORDS
   .

>= または <= は、値が論理的に最大値を超える可能性がある場合にのみ使用してください。あなたのものは決してできないので、EQUAL TOを使用してください。はい、それを超えると、ビッグ ファット ループが発生します。しかし、予期しないことが起こったときに「働く」よりはましです。> をテストして、診断メッセージで失敗した場合は問題ありません。一部のコンパイラでは、テーブル アクセスの「境界チェック」が可能です。これを使用している場合は、追加のチェックは必要ありません。

于 2013-02-04T10:34:29.880 に答える
2

私が正しく理解していれば、これはあなたが望むものに近いはずです

  220-MOVE-RECORDS.

       IF NAME-SUB >= 108
           perform varing i from 1 to 54
               MOVE NAME-1 (NAME-SUB) TO LEFT-LABEL
               compute ip54 = i + 54
               MOVE NAME-1 (ip54) TO RIGHT-LABEL

               WRITE NAMELIST-RECORD-OUT 
                from DETAIL-LINE
               AFTER ADVANCING 1 LINE
           end-perform

           MOVE SPACES TO DETAIL-LINE
           MOVE ZERO TO NAME-SUB
           PERFORM 300-WRITE-HEADING

    END-IF.

注: 多くの COBOL コンパイラでは小文字を使用できます

于 2013-02-04T05:19:41.143 に答える
1

コードだけでなく、ワーキング ストレージの定義を確認することも役に立ちました。一方を他方なしで理解するのは困難です。

いずれにせよ、あなたが説明しているのは、いくつかの可能な解決策があるかなり「標準的な」種類の問題です。以下は、考えられる 1 つのアプローチの概要です。

データ構造から始めます... 作業用ストレージ:

  01 WS-PAGE-BUFFER.
     02 WS-LINE OCCURS 54 TIMES.
        03 WS-NAME PIC X(40) OCCURS 2 TIMES.

上記の作業用ストレージは、出力の 1 ページを表します。このページには 54 行が含まれています。各行には 2 つの名前が含まれています。次に、いくつかのカウンターが必要です...

  01.
    02 WS-LINE-CNTR      PIC S9(4) COMP.
    02 WS-NAME-CNTR      PIC S9(4) COMP.

解決すべき 2 つの問題:

  • 適切な順序でページを埋める
  • 適切な見出し/予告編を含むページの印刷

これらの問題を解決するときに心に留めておくべきもう 1 つのことは、入力に関していくつかのシナリオをカバーする必要があるということです。したがって、何をするにしても、これらの状況はすべて「自然な」方法で解決する必要があります。また、一般に、解決すべき何らかのプリ/ポスト アンブルがあります (たとえば、初期化、ファイルを開く、ファイルを閉じるなど)。

もう 1 つ...入力/出力ファイルの FILE-STATUS を常に宣言して、エラーとファイルの終わりの状態をキャプチャします。以下のアルゴリズムは、それが完了していることを前提としています (ファイルの終わりステータスは通常「10」です)。

スケルトン アルゴリズム。

 MAINLINE
    PERFORM INITIALIZE-PAGE
    Open input file (check status etc...)
    Open output file (check status etc...)
    Read first line from file (check for errors/end of file etc...)
    PERFORM UNTIL INPUT-FILE-STATUS NOT = ZERO /* read until eof/error
       IF WS-LINE-CNTR = 54 AND WS-NAME-CNT = 2 /* check for full page.
          PERFORM OUTPUT-PAGE
       END-IF
       ADD +1 TO WS-LINE-CNTR
       IF WS-LINE-CNTR > 54
          MOVE +1 TO WS-LINE-CNTR /* Start next column...
          ADD +1 TO WS-NAME-CNTR  /* Increment column
       END-IF
       MOVE input-record TO WS-NAME (WS-LINE-CNTR, WS-NAME-CNTR)
       Read next line from input file
    END-PERFORM

    IF INPUT-FILE-STATUS = '10' AND WS-LINE-CNTR > ZERO
       PERFORM OUTPUT-PAGE /* force the last page to print
    END-IF

    close input file
    close output file

    GOBACK /* done 
    .

 INITIALIZE-PAGE.
     MOVE SPACE TO WS-PAGE-BUFFER  /* Blank page (ie. SPACES)
     MOVE ZERO TO WS-LINE-CNTR     /* Top of page 
     MOVE +1   TO WS-NAME-CNTR     /* First column of page
     .

 OUTPUT-PAGE.
     Ouput page headers...
     PERFORM VARYING WS-LINE-CNTR FROM 1 BY 1
               UNTIL WS-LINE-CNTR > 54
        write WS-LINE (WS-LINE-CNTR) to output file (check status etc...)
     END-PERORM
     Output page trailers...
     PERFORM INITIALIZE-PAGE /* Start a fresh page...
     .

埋めなければならない「空白の場所」をたくさん残しました。あなたがやろうとしていることを達成するためのもっと洗練された方法が他にもあることは認めますが、これで始めることができます。

于 2013-02-04T17:14:39.077 に答える