当位置未知时,如何从文件中获取COBOL中的字符串?

时间:2013-08-06 23:36:58

标签: cobol cobol85

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

LENGTH(14909135) FILEID(DD:EDIREC) MSGDATE(130723) MSGDATELONG(20130723)
MSGTIME(091053) MSGSEQO(001390) MSGNAME(00008557) MSGSEQNO(00001)
SESSIONKEY(XXXXXXXX) DELIMITED(E) SYSNAME(XXXXX-XX) SYSLEVEL(XXXX) TIMEZONE(L)
DATATYPE(E) EDITYPE(XXX) SENDERFILE(#####) RECFM(????) RECLEN(#) RECDLM(E)
UNIQUEID(XXXXXXXX) SYSTYPE(##) SYSVER(#);
RECEIVED ACCOUNT(XXXX) USERID(XXXXXXXX) CLASS(#E2) CHARGE(3) LENGTH(14911043)
FILEID(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(UNFORMATTED)
SENDERFILE(XXXXXXXXXXXXX) RECFM(????) RECLEN(0) RECDLM(C) UNIQUEID(XXXXXXXX)
SYSTYPE(24) SYSVER(5);

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

    WORKING-STORAGE SECTION.

    01 WS-INPUT-RECORD   PIC X(80).

    01 WS-STRINGS.

       05 LENGTH-STRING      PIC X(7) VALUE 'LENGTH('.

    01 WS-COUNTERS.

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

    01 WS-CHAR-TOTALS.

       05 CHAR-TOTAL  PIC 9(11) VALUE ZEROS.

       05 TMP-TOTAL  PIC X(11) VALUE ZEROS.

    ......

    PROCEDURE DIVISION.

    2200-GET-MSG-TOTAL.

        INSPECT WS-INPUT-RECORD
        TALLYING WS-MSG-COUNT FOR ALL LENGTH-STRING.

    2300-CHAR-TOTAL.

        IF WS-INPUT-RECORD(1:7) = LENGTH-STRING

           MOVE WS-INPUT-RECORD(8:9) TO TMP-TOTAL

           UNSTRING TMP-TOTAL DELIMITED BY ')'
           INTO CHAR-TOTAL

        END-IF

        IF WS-INPUT-RECORD(61:7) = LENGTH-STRING

           MOVE WS-INPUT-RECORD(68:9) TO TMP-TOTAL

           UNSTRING TMP-TOTAL DELIMITED BY ')'
               INTO CHAR-TOTAL

        END-IF

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

3 个答案:

答案 0 :(得分:2)

使用INSPECT建立LENGTH(在当前记录中。

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

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

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

放弃目的地字段-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查看“字符串”是否存在的技术可以应用于接受的其他解决方案,这样只有当行包含所需的值时才会“搜索”。

答案 1 :(得分: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 
       . 

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 .

答案 2 :(得分:0)

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

   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
       .

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 .