如何通过COBOL或实用程序实现数据集的子串匹配去重
实现方法:COBOL 与 DFSORT(实用程序)
一、COBOL 实现思路与代码示例
核心逻辑:加载所有记录到内存(数据量过大时可改用磁盘排序分块处理),逐个检查每条记录是否是其他任意记录的子串,仅保留不被任何记录包含的条目。
步骤说明
- 读入并去重:将输入文件的所有记录读入数组,同时跳过重复记录。
- 子串检测:对每条记录,遍历其他所有记录,判断当前记录是否是某条其他记录的子串。
- 写入有效记录:若当前记录不被任何其他记录包含,则写入输出文件。
简化代码示例
IDENTIFICATION DIVISION. PROGRAM-ID. FILTER-SUBSTRINGS. ENVIRONMENT DIVISION. INPUT-OUTPUT SECTION. FILE-CONTROL. SELECT INFILE ASSIGN TO INPUT-FILE ORGANIZATION IS LINE SEQUENTIAL. SELECT OUTFILE ASSIGN TO OUTPUT-FILE ORGANIZATION IS LINE SEQUENTIAL. DATA DIVISION. FILE SECTION. FD INFILE. 01 IN-RECORD PIC X(100). FD OUTFILE. 01 OUT-RECORD PIC X(100). WORKING-STORAGE SECTION. 01 REC-ARRAY. 05 REC-ENTRY OCCURS 1000 TIMES INDEXED BY REC-IDX. 10 REC-DATA PIC X(100). 01 TOTAL-RECS PIC 9(4) VALUE 0. 01 I PIC 9(4) VALUE 0. 01 J PIC 9(4) VALUE 0. 01 IS-SUBSTRING PIC X(1) VALUE 'N'. 01 WS-COUNT PIC 9(4) VALUE 0. PROCEDURE DIVISION. MAIN-PARA. OPEN INPUT INFILE OUTPUT OUTFILE. *> 读入所有记录到数组 PERFORM UNTIL INFILE-STATUS = 10 READ INFILE AT END MOVE 10 TO INFILE-STATUS NOT AT END ADD 1 TO TOTAL-RECS MOVE IN-RECORD TO REC-DATA(TOTAL-RECS) END-PERFORM. *> 去重处理 PERFORM VARYING I FROM 1 BY 1 UNTIL I > TOTAL-RECS PERFORM VARYING J FROM I+1 BY 1 UNTIL J > TOTAL-RECS IF REC-DATA(I) = REC-DATA(J) MOVE SPACES TO REC-DATA(J) END-IF END-PERFORM END-PERFORM. *> 过滤子串记录 PERFORM VARYING I FROM 1 BY 1 UNTIL I > TOTAL-RECS IF REC-DATA(I) NOT = SPACES MOVE 'N' TO IS-SUBSTRING PERFORM VARYING J FROM 1 BY 1 UNTIL J > TOTAL-RECS OR IS-SUBSTRING = 'Y' IF I NOT = J AND REC-DATA(J) NOT = SPACES INSPECT REC-DATA(J) TALLYING WS-COUNT FOR ALL REC-DATA(I) IF WS-COUNT > 0 MOVE 'Y' TO IS-SUBSTRING END-IF MOVE 0 TO WS-COUNT END-IF END-PERFORM IF IS-SUBSTRING = 'N' MOVE REC-DATA(I) TO OUT-RECORD WRITE OUT-RECORD END-IF END-IF END-PERFORM. CLOSE INFILE OUTFILE. STOP RUN.
注:若输入数据量极大,需改用磁盘排序+分块处理避免内存溢出;可根据实际记录长度调整
PIC X(100)的长度。
二、实用程序(DFSORT)实现思路与JCL示例
大型机环境下可直接用DFSORT实现,核心是先按记录长度降序排序,再过滤掉被更长记录包含的子串记录。
步骤说明
- 添加长度标识:给每条记录前追加自身长度值,便于排序和判断。
- 按长度降序排序:确保更长的记录排在前面,只需检查当前记录是否被前面的长记录包含即可。
- 过滤子串记录:用DFSORT的子串搜索功能,排除那些是前面任意记录子串的条目。
JCL示例
//FILTERSUB EXEC PGM=ICETOOL //TOOLMSG DD SYSOUT=* //DFSMSG DD SYSOUT=* //INFILE DD DSN=YOUR.INPUT.FILE,DISP=SHR //OUTFILE DD DSN=YOUR.OUTPUT.FILE,DISP=(NEW,CATLG,DELETE), // SPACE=(CYL,(5,5),RLSE) //TOOLIN DD * COPY FROM(INFILE) TO(TEMP1) USING(CTL1) SORT FROM(TEMP1) TO(TEMP2) USING(CTL2) COPY FROM(TEMP2) TO(OUTFILE) USING(CTL3) /* //CTL1 DD * INREC BUILD=(1,100,101:80X,109:LENGTH(1,100),TO=ZD,LENGTH=4) *> 1-100:原记录;109-112:记录长度(ZD格式) /* //CTL2 DD * SORT FIELDS=(109,4,ZD,D) *> 按记录长度降序排序 /* //CTL3 DD * OUTFIL FNAMES=OUTFILE, INCLUDE=(1,100,SS,NE,SHIFT=LEFT, OVERLAY=(101:1,100), START=1,END=100), BUILD=(1,100) *> SS,NE表示当前记录不是前面任何记录的子串时保留 /*
注:若记录长度超过100,需调整对应位置的偏移量;需使用支持
SS子串搜索功能的DFSORT版本。
内容的提问来源于stack exchange,提问作者Ashish
相关产品推荐
相关产品推荐

