2013-08-06 4 views
1

나는 COBOL뿐만 아니라이 사이트를 처음 사용합니다. 80 바이트 파일을 읽고 특정 문자열을 찾고 그 바로 뒤에있는 다른 문자열을 잡는 프로그램을 작성하려고합니다. 내가 가지고있는 유일한 문제는 문자열의 시작 위치가 파일 전체에서 항상 같은 바이트에있는 것은 아니라는 것입니다.위치를 모르는 경우 파일에서 COBOL로 문자열을 가져 오는 방법은 무엇입니까?

 
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); 

주의 두 길이 (#####) 문자열 예를 들어, 내가 아래 찾기 위해 노력하고있는 문자열은 파일 전체를 두 번 표시되는 길이 (#####) 문자열입니다. 아래 코드는 길이 문자열이 나타나는 횟수를 계산하는 것은 물론 최종 길이 문자열 수 (실제로 원하는 길이 문자열 내의 수)를 가져 오지만이 두 위치에있을 때만 처리합니다.

 
    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 (####)가 다른 바이트 위치에서 끝나면 작동하지 않습니다. 문자열에 대한 파일의 모든 바이트를 검사하는 IF 문을 코딩하는 것 외에 길이가 길어지면 그 값을 가져 오는 더 쉬운 방법이 있습니까? 다른 게시물을 많이 확인하고 포인터 또는 테이블을 사용하는 것에 대해 생각해 보았습니다.하지만 실제로 이해할 수는 없습니다.

+0

PERFORM 코드를 사용하는 경우 최소한 하나가 있다는 것을 알고있을 때만 검색하도록 INSPECT를 포함합니다. INSPECT를 원하지 않는다면, "length of input-9"부터 시작하여 "뒤에서"루프를 수행하십시오. 가능한 가장 짧은 문자열을 얻을 수 있습니다. 최소값을 알고 있으면 수정하십시오. "해지"는 쉽습니다. 0에 도달하면 멈 춥니 다.INSPECT는 많은 프로세싱을 저장하지만, 파일 크기가 그리 크지 않기 때문에 다음과 같이 알아볼 수 있습니다. :-)하지만 적어도 다음에 복사 할 때 효율적인 코드를 얻습니다. –

답변

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 
     . 

+0

감사합니다! 나는 이것을 줄 것이다 –

+0

이것은 위대한 일을했지만 나는 'LENGTH ('가 나타날 수있는 마지막 위치이기 때문에 68로 RECORD-LENGTH 변수를 변경해야한다고 언급 할 것이라고 생각했다. 80, 그것이 기록의 범위를 벗어 났기 때문에 비정상이 발생했습니다. 감사합니다. –

+0

감사합니다. Bill. 귀하의 의견을 바탕으로 더 나은 해결책을 게시 할 것입니다. –

2

를 사용하여 현재 레코드에 (즉 길이를 설정 INSPECT는

만있는 경우, 다음을 수행하십시오

긴장을 풀다 사용하여 길이를 (두 개의 수신 필드가있는 구분 기호로 사용)

UNSTRING 두 번째 수신 필드는 다음으로 구분됩니다. 번호는 사용자에게 남겨 둡니다.)

예 617,451,515,

는 :

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- 포기. 두 번째 UNSTRING에 대한 입력에는 destination-field-2를 사용하십시오.

예제를 조명하기 위해 표시된 이름보다는 의미있는 이름을 사용하십시오.

그래서

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 
       "<" 
     . 

은 "문자열"라인이 원하는 값이 인이 포함되어있는 경우에만 "검색"되도록 허용 다른 솔루션에 적용 할 수있을 경우, 볼이 검토와 기술 .

+0

의견을 보내 주셔서 감사합니다. 빠른 질문. 어떻게 하시겠습니까? LENGTH (두 수신 필드가있는 구분 기호로 사용? –

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 
     .