1

我是该网站和 COBOL 的新手。我正在尝试编写一个程序,它读取一个 80 字节的文件,并找到一个特定的字符串并抓住另一个紧随其后的字符串。我遇到的唯一问题是字符串的起始位置并不总是在整个文件中的同一字节中。例如,我试图在下面找到的字符串是在整个文件中出现两次的 LENGTH(#####) 字符串:

长度(14909135)文件ID(DD:EDIREC)MSGDATE(130723)MSGDATELONG(20130723)
MSGTIME(091053) MSGSEQO(001390) MSGNAME(00008557) MSGSEQNO(00001)
SESSIONKEY(XXXXXXXX) DELIMITED(E) 系统名(XXXXX-XX) 系统级(XXXX) 时区(L)
DATATYPE(E) EDITYPE(XXX) SENDERFILE(#####) RECFM(??????) RECLEN(#) RECDLM(E)
UNIQUEID(XXXXXXXX) SYSTYPE(##) SYSVER(#);
收到的帐户(XXXX)用户ID(XXXXXXXX)类别(#E2)费用(3)长度(14911043)
文件ID(DD:EDIREC)MSGDATE(130723)MSGDATELONG(20130723)MSGTIME(093045)
MSGSEQO(001392) MSGSEQNO(00000) SESSIONKEY(XXXXXXXX) DELIMITED(C)
SYSNAME(XXXXX-XX) SYSLEVEL(XXXX) TIMEZONE(L) DATATYPE(E) EDITYPE(未格式化)
SENDERFILE(XXXXXXXXXXXXX) RECFM(????) RECLEN(0) RECDLM(C) UNIQUEID(XXXXXXXX)
SYSTYPE(24) SYSVER(5);

注意两个 LENGTH(#####) 字符串。下面的代码设法计算长度字符串出现的次数以及获取最终长度字符串计数(我真正想要的,长度字符串中的数字),但仅当它们位于这两个位置时:

    工作存储部分。

    01 WS-输入-记录图片 X(80)。

    01 WS-字符串。

       05 长度字符串 PIC X(7) 值 'LENGTH('.

    01 WS-计数器。

       05 WS-MSG-COUNT PIC 9(11)。

    01 WS-CHAR-TOTALS。

       05 CHAR-TOTAL PIC 9(11) 值为零。

       05 TMP-TOTAL PIC X(11) 值为零。

    ……

    程序部。

    2200-获取-味精-总计。

        检查 WS-INPUT-RECORD
        统计所有长度字符串的 WS-MSG-COUNT。

    2300-CHAR-TOTAL。

        如果 WS-INPUT-RECORD(1:7) = 长度字符串

           将 WS-INPUT-RECORD(8:9) 移动到 TMP-TOTAL

           UNSTRING TMP-TOTAL 由 ')' 分隔
           INTO CHAR-TOTAL

        万一

        如果 WS-INPUT-RECORD(61:7) = 长度字符串

           将 WS-INPUT-RECORD(68:9) 移动到 TMP-TOTAL

           UNSTRING TMP-TOTAL 由 ')' 分隔
               INTO CHAR-TOTAL

        万一

该代码适用于上面示例输入中显示的两个位置。但如果 LENGTH(####) 以任何其他字节位置结束,它将不起作用。除了编写 80 个 IF 语句来检查文件中每个字节的字符串之外,还有没有更简单的方法可以在长度括号内获取这些值?我检查了很多其他帖子,并考虑过使用指针或表格,但我似乎不太明白。

4

3 回答 3

2

使用 INSPECT 确定 LENGTH( 在当前记录上。

仅当存在时,执行以下操作:

UNSTRING 使用 LENGTH( 作为具有两个接收字段的分隔符。

UNSTRING 由 ) 分隔的第二个接收字段,为您留下号码。

例如:

01  delimiting-field PIC X(7) VALUE "LENGTH(".
01  desitnation-field-1 PIC X.
01  destination-field-2 PIC X(18) JUST RIGHT.

UNSTRING source-field DELIMITED BY delimiting-field INTO desitnation-field-1
                                                         destination-field-2

放弃destination-field-1。使用destination-field-2 输入第二个UNSTRING。

使用有意义的名称,而不是我为说明示例而展示的名称。

所以,

    01  WS-INPUT-RECORD                     PIC X(80). 
    01  NUMBER-OF-LENGTHS            BINARY PIC 9(4). 
    01  DELIMITER-COUNT              BINARY PIC 9(4). 
        88  NO-DELIMITERS                   VALUE ZERO. 
        88  ONE-DELIMITER                   VALUE 1. 
    01  LENGTH-OPEN-PAREN                   PIC X(7) 
                                            VALUE "LENGTH(". 
    01  DATA-TO-IGNORE                      PIC X. 
    01  DATA-WITH-LENGTH-VALUE              PIC X(80). 
    01  CLOSING-PAREN                       PIC X VALUE ")". 
    01  VALUE-OF-LENGTH-AN                  PIC X(18) JUST RIGHT.

   THE-STUFF. 
       SET NO-DELIMITERS            TO TRUE 
       INSPECT WS-INPUT-RECORD      TALLYING DELIMITER-COUNT 
                                     FOR ALL LENGTH-OPEN-PAREN
       EVALUATE TRUE 
           WHEN NO-DELIMITERS 
               CONTINUE 
           WHEN ONE-DELIMITER 
               PERFORM              GET-THE-DATA 
           WHEN OTHER 
               PERFORM              OH-DEAR-MORE-THAN-ONE 
       END-EVALUATE 
       . 
   GET-THE-DATA. 
       UNSTRING WS-INPUT-RECORD     DELIMITED BY 
                                    LENGTH-OPEN-PAREN 
           INTO                     DATA-TO-IGNORE 
                                    DATA-WITH-LENGTH-VALUE 
       UNSTRING DATA-WITH-LENGTH-VALUE 
                                    DELIMITED BY CLOSING-PAREN
           INTO                     VALUE-OF-LENGTH-AN 
       DISPLAY "THIS IS WHAT WE FOUND" 
       DISPLAY ">" 
               VALUE-OF-LENGTH-AN 
               "<" 
       . 
   OH-DEAR-MORE-THAN-ONE. 
       DISPLAY "THE FOLLOWING LINE HAS MORE THAN ONE LENGTH(" 
       DISPLAY ">" 
               WS-INPUT-RECORD 
               "<" 
       . 

使用 INSPECT 查看“字符串”是否存在的技术可以应用于接受的其他解决方案,这样只有当该行包含所需的值时才会“搜索”它。

于 2013-08-07T07:40:36.623 回答
1

您可以使用“执行变化”循环来查看每行中字符串的每个块,其中每个块是一个字符串,即您要查找的字符串的长度。下面是一个适用于 OpenCobol 的示例:

   IDENTIFICATION DIVISION.
   PROGRAM-ID. FIND-STRING.

   ENVIRONMENT DIVISION.
   INPUT-OUTPUT SECTION.
   FILE-CONTROL.
   SELECT IN-FILE ASSIGN TO 'SAMPLE-LEN.TXT'
       ORGANIZATION IS LINE SEQUENTIAL.

   DATA DIVISION.
   FILE SECTION.
   FD  IN-FILE.
   01  IN-RECORD                        PIC X(80).

   WORKING-STORAGE SECTION.
   01  END-OF-FILE-SWITCH               PIC XXX VALUE 'NO '.
       88  END-OF-FILE                  VALUE 'YES'.
   01  STRING-MARKER                    PIC X(7) VALUE 'LENGTH('.
   01  STRING-MARKER-LENGTH             PIC 99 VALUE 7.
   01  STRING-SOUGHT                    PIC X(11).
   01  STRING-INDEX                     PIC 99.
   01  RECORD-LENGTH                    PIC 99 VALUE 80.

   PROCEDURE DIVISION.
   MAIN.
       OPEN INPUT IN-FILE
       PERFORM UNTIL END-OF-FILE
           READ IN-FILE
               AT END
                   SET END-OF-FILE TO TRUE
               NOT AT END
                   PERFORM FIND-STRING
           END-READ
       END-PERFORM
       CLOSE IN-FILE
       STOP RUN
       .

   FIND-STRING.
       PERFORM VARYING STRING-INDEX FROM 1 BY 1
           UNTIL STRING-INDEX > (RECORD-LENGTH
                                 - STRING-MARKER-LENGTH)
           IF IN-RECORD(STRING-INDEX:STRING-MARKER-LENGTH) =
              STRING-MARKER
              UNSTRING IN-RECORD(STRING-INDEX
                                 + STRING-MARKER-LENGTH : 10)
                  DELIMITED BY ')' INTO STRING-SOUGHT 
              END-UNSTRING 
              DISPLAY STRING-SOUGHT END-DISPLAY 
           END-IF 
       END-PERFORM 
       . 

于 2013-08-07T02:53:15.247 回答
0

根据 Bill Woodger 的评论,这里有一个更好的解决方案。谢谢比尔,教我不要懒散:) 我仍然喜欢循环遍历每条记录,以在一条线上捕捉多个匹配项,所以我保留了这部分。

   IDENTIFICATION DIVISION.
   PROGRAM-ID. FIND-STRING-2.

   ENVIRONMENT DIVISION.
   INPUT-OUTPUT SECTION.
   FILE-CONTROL.
   SELECT IN-FILE ASSIGN TO 'SAMPLE-LEN.TXT'
       ORGANIZATION IS LINE SEQUENTIAL
       FILE STATUS IS IN-FILE-STATUS.

   DATA DIVISION.
   FILE SECTION.
   FD  IN-FILE.
   01  IN-RECORD                        PIC X(80).

   WORKING-STORAGE SECTION.
   01  IN-FILE-STATUS                   PIC XX.
   01  END-OF-FILE-SWITCH               PIC XXX VALUE 'NO '.
       88  END-OF-FILE                  VALUE 'YES'.
   01  STRING-MARKER-LEFT               PIC X(7) VALUE 'LENGTH('.
   01  STRING-MARKER-RIGHT              PIC X VALUE ')'.
   01  STRING-MARKER-LENGTH             PIC 99 USAGE BINARY.
   01  STRING-INDEX                     PIC 99 USAGE BINARY.
   01  START-INDEX                      PIC 99 USAGE BINARY.
   01  END-INDEX                        PIC 99 USAGE BINARY.
   01  RECORD-LENGTH                    PIC 99 USAGE BINARY.
   01  SEARCH-LENGTH                    PIC 99 USAGE BINARY.
   01  IS-END-FOUND                     PIC XXX VALUE 'NO '.
       88  END-FOUND                    VALUE 'YES'.
       88  END-NOT-FOUND                VALUE 'NO '.

   PROCEDURE DIVISION.
   MAIN.
       OPEN INPUT IN-FILE

       IF IN-FILE-STATUS NOT = '00'
           DISPLAY 'FILE READ ERROR ' IN-FILE-STATUS
           END-DISPLAY
           PERFORM EXIT-PROGRAM
       END-IF

       PERFORM INITIALIZE-LENGTHS

       PERFORM UNTIL END-OF-FILE
           READ IN-FILE
               AT END 
                   SET END-OF-FILE TO TRUE
               NOT AT END
                   PERFORM FIND-STRING
           END-READ
       END-PERFORM
       PERFORM EXIT-PROGRAM
       .

   INITIALIZE-LENGTHS.
       MOVE FUNCTION LENGTH(IN-RECORD) TO RECORD-LENGTH 
       COMPUTE STRING-MARKER-LENGTH = FUNCTION LENGTH(
           STRING-MARKER-LEFT)
       END-COMPUTE
       COMPUTE SEARCH-LENGTH = RECORD-LENGTH - STRING-MARKER-LENGTH
       END-COMPUTE
       .

   FIND-STRING.
       PERFORM VARYING STRING-INDEX FROM 1 BY 1
           UNTIL STRING-INDEX > SEARCH-LENGTH 
           IF IN-RECORD(STRING-INDEX:STRING-MARKER-LENGTH) =
              STRING-MARKER-LEFT
              COMPUTE START-INDEX = STRING-INDEX 
                  + STRING-MARKER-LENGTH
              END-COMPUTE
              SET END-NOT-FOUND TO TRUE
              PERFORM VARYING END-INDEX FROM START-INDEX BY 1 
              UNTIL END-INDEX > RECORD-LENGTH OR END-FOUND
                  IF IN-RECORD(END-INDEX:
                  FUNCTION LENGTH(STRING-MARKER-RIGHT)) = 
                  STRING-MARKER-RIGHT
                      SET END-FOUND TO TRUE
                  END-IF
              END-PERFORM
              COMPUTE END-INDEX = END-INDEX - START-INDEX - 1
              END-COMPUTE
              DISPLAY IN-RECORD(START-INDEX:END-INDEX)
              END-DISPLAY
           END-IF
       END-PERFORM
       .

   EXIT-PROGRAM.
       CLOSE IN-FILE
       STOP RUN
       .

于 2013-08-09T02:05:50.600 回答