2

我们应该形成一个出现 108 次的名称数组。我们应该在左栏中有名称 1-54,在右栏中有名称 55-108。一页有 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 行并重复。所以两个循环;读取 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

如果我理解正确,这应该接近你想要的

  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 回答
2

您应该始终对所有 IO 进行错误检查。

一个文件入一个文件输出总是看起来像这样:

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

“启动读取”处理文件上的第一条记录(如果有的话)。您可以巧妙地处理“空文件”,而不必“混淆”您的主要逻辑或在别处区分两种不同类型的“文件结尾”。“进程文件”末尾的现在读取消除了有些曲折的“AT END/NOT AT END”。

例如,您的表中只需要54 个元素。在处理页面“右侧”的记录时,您可以从“左侧”中取第一个并立即执行该行。

使用 88s 而不是文字进行测试。

不要在页面末尾添加“标题”,因为好像没有更多记录要处理,标题后面会出现“空白页”。

如果您的打印行的写入在一个段落中,则可以使用该段落检查是否需要标题,“行数”的初始值为 54。

使用一次打印一页的 108 元素方法,在顶部做标题。

如果数据在设置为其他值之前从未使用过,则无需将其设置为初始值。

您已经对程序代码采用了“最小句号/句号”方法,这很好 - 将必要的最后一个句点单独放在一行中怎么样?

   PERFORM 220-MOVE-RECORDS.

变成

   PERFORM 220-MOVE-RECORDS
   .

仅当值在逻辑上可以超过最大值时才使用 >= 或<=。你的永远不可能,所以使用 EQUAL TO。是的,如果超过,你会得到一个大胖圈。但这比在发生意外情况时“工作”要好。如果您想测试 > 是否超出然后失败并显示诊断消息,那没关系。一些编译器允许对表访问进行“边界检查”,如果你使用它,你甚至不需要额外的检查。

于 2013-02-04T10:34:29.880 回答
1

查看您的工作存储定义以及代码会很有帮助。没有另一个很难理解。

无论如何,您所描述的是一个相当“标准”的问题,有几种可能的解决方案。以下是一种可能方法的概述。

从数据结构开始......工作存储:

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

上面的工作存储描述了一页输出。该页面包含 54 行。每行包含两个名称。接下来你需要几个柜台......

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

要解决的两个问题:

  • 以正确的顺序填充页面
  • 打印带有适当标题/预告片的页面

解决这些问题时要记住的另一件事是,您需要涵盖与输入相关的几个场景:无输入,输入恰好适合某些数量的输出页面,输入部分填充输出页面。所以无论你做什么,所有这些情况都需要以一种“自然”的方式来解决。此外,通常需要解决某种前/后同步信号(例如初始化、打开文件、关闭文件等)。

还有一件事......始终为您的输入/输出文件声明一个 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 回答