当位置未知时,如何从文件中获取COBOL格式的字符串?
我对这个网站和COBOL都是新手。我试图编写一个程序,读入一个80字节的文件,找到一个特定的字符串,然后抓取另一个紧跟其后的字符串。我遇到的唯一问题是,字符串的起始位置在整个文件中并不总是在同一字节中。例如,我试图在下面查找的字符串是在整个文件中出现两次的长度(######)字符串: 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); 长度(14909135)文件ID(DD:EDIREC)MSGDATE(130723)MSGDATELONG(20130723) MSGTIME(091053)MSGSEQO(001390)MSGNAME(00008557)MSGSEQNO(00001) 会话密钥(XXXXXXXX)分隔(E)系统名(XXXXX-XX)系统级(XXXXX)时区(L) 数据类型(E)编辑类型(XXX)发送器文件(E)RECFM(??)RECEN(E) UNIQUEID(XXXXXXXX)系统类型(##)系统版本(#); 已接收帐户(XXXX)用户ID(XXXXXXXX)类别(#E2)费用(3)长度(14911043) 文件ID(DD:EDIREC)MSGDATE(130723)MSGDATELONG(20130723)MSGTIME(093045) MSGSEQO(001392)MSGSEQNO(00000)会话密钥(XXXXXXXX)分隔(C) 系统名称(XXXXX-XX)系统级别(XXXX)时区(L)数据类型(E)编辑类型(未格式化) 发送方文件(XXXXXXXXXXXX)RECFM(??)RECEN(0)RECDLM(C)唯一ID(XXXXXXXX) 系统类型(24)系统版本(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 工作和储存科。 01 WS-INPUT-RECORD PIC X(80)。 01 WS-STRINGS。 05长度字符串PIC X(7)值“长度(”。 01个WS-COUNTERS。 05 WS-MSG-COUNT图9(11)。 01 WS-CHAR-TOTALS。 05字符-总PIC 9(11)值为零。 05 TMP-总PIC X(11)值为零。 ...... 程序司。 2200-GET-MSG-TOTAL。 检查WS-INPUT-RECORD 统计所有长度字符串的WS-MSG-COUNT。 总共2300个字符。 如果WS-INPUT-RECORD(1:7)=长度字符串 将WS-INPUT-RECORD(8:9)移动到TMP-TOTAL 解压TMP-TOTAL,以“')分隔 转换为字符总数 端到端IF 如果WS-INPUT-RECORD(61:7)=长度字符串 将WS-INPUT-RECORD(68:9)移动到TMP-TOTAL 解压TMP-TOTAL,以“')分隔 转换为字符总数 端到端IF 该代码对于上面输入示例中显示的两个位置非常有效。但如果长度(######)结束于任何其他字节位置,则它将不起作用。除了编码80个IF语句来检查文件中每个字节的字符串外,还有更简单的方法来获取长度参数中的值吗?我查看了很多其他帖子,并考虑过使用指针或表格,但我似乎不太明白。您可以使用“执行变化”循环查看每行中字符串的每个块,其中每个块都是一个字符串,即您要查找的字符串的长度。下面是一个在OpenCobol中工作的示例:当位置未知时,如何从文件中获取COBOL格式的字符串?,cobol,cobol85,Cobol,Cobol85,我对这个网站和COBOL都是新手。我试图编写一个程序,读入一个80字节的文件,找到一个特定的字符串,然后抓取另一个紧跟其后的字符串。我遇到的唯一问题是,字符串的起始位置在整个文件中并不总是在同一字节中。例如,我试图在下面查找的字符串是在整个文件中出现两次的长度(######)字符串: LENGTH(14909135) FILEID(DD:EDIREC) MSGDATE(130723) MSGDATELONG(20130723) MSGTIME(091053) MSGSEQO(001390) MS
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
.
使用INSPECT来确定当前记录上的长度
仅当存在时,执行以下操作:
使用长度(作为带有两个接收字段的分隔符)解除拉伸
取消对第二个接收字段的排序,该字段由分隔符)分隔,并将数字留给您
例如:
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作为第二次解编的输入
使用有意义的名称,而不是我所展示的那些来说明示例
所以
01 WS-INPUT-RECORD PIC X(80)。
01长度数二进制PIC 9(4)。
01分隔符计数二进制PIC 9(4)。
88个无分隔符值为零。
88单分隔符值1。
01长度-开口-帕伦图X(7)
值“长度(”。
01数据忽略图X。
01数据长度值PIC X(80)。
01收盘价(PIC X值“)。
01长度值一张图片X(18)正好。
最重要的事。
将无分隔符设置为TRUE
检查WS-INPUT-RECORD计数分隔符计数
适用于所有长度的开放式排列
评价真实
当没有分隔符时
继续
当一个分隔符
执行获取数据
当其他
表演哦,天哪,不止一个
最终评估
.
获取最新数据。
取消对由分隔符分隔的WS-INPUT记录的排序
长度开环
进入数据到忽略状态
数据长度值
使用长度值解列数据
由CLOSING-PAREN分隔
转化为长度的值
显示“这就是我们发现的”
显示“>”
长度值
""
WS-INPUT-RECORD
“根据比尔·伍德格的评论,这里有一个更好的解决方案。感谢比尔的比尔,教我不要懈怠:)我仍然喜欢循环浏览每一张唱片,作为在一行捕捉多个匹配项的一种方式,所以我保留了那部分。
谢谢!我会试一试这很有效,但我想我应该提到,我必须将记录长度变量更改为68,因为这是最后一个“长度”的位置('可能会出现。当我以80开始尝试它时,它导致异常终止,因为它超出了记录的范围。再次感谢!谢谢,比尔。我将根据您的评论发布一个更好的解决方案。谢谢您的评论,尽管是快速问题。您如何使用长度(作为带有两个接收字段的分隔符?如果您使用执行代码,我将包括INSP
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
"<"
.
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
.