【问题标题】:Ignoring commas within quotes in a COBOL formatting program在 COBOL 格式化程序中忽略引号内的逗号
【发布时间】:2019-04-12 10:42:08
【问题描述】:

我的办公室使用了一个内部工具,该工具可以从 DDL 生成 COBOL 格式化程序、COBOL 文件到 DB2 加载程序和其他相关对象。 通常,我们加载的文件用“|”分隔但是新的数据源只发送用逗号分隔的文件。

我遇到的问题是某些文本字段中包含逗号,格式化程序在读取输入数据中的记录后执行的第一件事是运行检查/计数以检查分隔符的正确数量记录。如果计算的分隔符太多,则丢弃该记录。当逗号在文本字段中时,它会失败记录,因为它无法区分字段中的逗号和分隔符之间的区别。

幸运的是,所有文本字段都用引号括起来 " 所以我打算编写一些代码来检查记录中的每个字符,一次记录一个引号,如果遇到逗号和引号计数是一个奇数,它会忽略逗号而不将其计入计数中。

关于如何做到这一点的任何建议?

【问题讨论】:

  • 我们可以假设 z/OS,还是 LUW DB2?
  • 哦,是的,对不起,我忘了它是 z/OS
  • 可以按照您概述的方式在 COBOL 中执行此操作,但您可能需要考虑使用 SORT 来执行文件的接受/拒绝。您可以计算逗号,计算引号,逗号减(引号除以二)是字段数。如果您想考虑这一点,您可以使用 DFSORT 或 SyncSORT 标签(取决于您拥有的标签)提出另一个问题,并包括对您拥有的产品版本的引用。
  • 不要忘记在文本字段中嵌入 "。
  • 感谢您的建议,但只有字符字段有引号,整数和数据字段没有引号,它们的两边只有一个逗号来分隔它们。

标签: csv cobol zos


【解决方案1】:

这假设您知道在线上有多少数据(如果是可变长度,则为最大数据长度),并且您将用该行的最大长度替换 OCCURS 1000 .

这个想法是使用一个开关。 EVALUATE 中的第一件事是检查报价。如果找到,请拨动开关。接下来就是说如果开关打开,忽略这个字节。接下来是,如果是逗号,数一下。

PERFORM 完成后,-count 将包含非引号限制逗号的总数。

我选择的数据名称是为了说明该技术。您将这些更改为与您的任务相关。

01  length-of-data-on-the-line 
                              COMP PIC 9(4).

01  the-line.
    05  FILLER OCCURS 1000 TIMES.
        10  character-on-the-line  PIC X.
            88  cotl-is-comma      VALUE COMMA.
            88  cotl-is-quote      VALUE QUOTE.

01  FILLER.
    05  FILLER                     PIC X.
        88  on-off-switch-on       VALUE "1".
        88  on-off-switch-off      VALUE "7".

01  the-count                 COMP PIC 9(4).
01  data-on-line-sub          COMP PIC 9(4).


MOVE ZERO                   TO the-count
                               data-on-line-sub
SET on-off-switch-off       TO TRUE
PERFORM 
  length-of-data-on-the-line TIMES
    ADD 1                   TO data-on-line-sub
    EVALUATE TRUE
      WHEN cotl-is-quote ( data-on-line-sub )
        IF on-off-switch-off
            SET on-off-switch-on
                             TO TRUE
        ELSE
            SET on-off-switch-off
                             TO TRUE
        END-IF
      WHEN on-off-switch-on
        CONTINUE
      WHEN cotl-is-comma ( data-on-line-sub )
        ADD 1                TO the-count
    END-EVALUATE
END-PEFORM

【讨论】:

  • 好的,为此欢呼,有道理,看起来会奏效。我得到了一份正在做这项工作的 selcopy。一旦它实现并运行,我将尝试将它添加到代码中以删除运行 selcopy 的额外步骤。我认为最好将它们全部保存在一个程序中。
  • @mmackenzie93 一定要使用 QUOTE 选项而不是 APOST 选项进行编译。
  • @mmackenzie93 cschneid 的评论归结为我使用了比喻常量 QUOTE,它与编译器选项 QUOTE 将使用 ",而与 APOST 将使用 '。如果人们容易混淆该编译器选项,那么您还有其他两种方法可以做到这一点。 VALUE '"',或使用十六进制值。明天我可能会用这个更新我的答案。
【解决方案2】:

虽然超出了要求,但该程序应该可以处理大多数 CSV 记录。它没有使用制表符分隔符进行测试。该程序将 CSV 文本(删除添加的引号)从由选定分隔符分隔的分隔符转换为由 LOW-VALUES 分隔的分隔符。使用UNSTRING ... DELIMITED LOW-VALUES INTO ... 更容易分隔字段。

   IDENTIFICATION DIVISION.
   PROGRAM-ID. CSV2STR.
   DATA DIVISION.
   WORKING-STORAGE SECTION.
   01  I COMP PIC 9(4).
   01  J COMP PIC 9(4).
   01  FLD-START COMP PIC 9(4).
   01  STATE COMP PIC 9(4).
   01  FLD-SEP PIC X VALUE LOW-VALUES.
   01  QUOT PIC X VALUE """".
   01  APOS PIC X VALUE "'".
   01  COMM PIC X VALUE ",".
   LINKAGE SECTION.
   01  INPUT-REC PIC X(2000).
   01  INPUT-LENGTH COMP PIC 9(4).
   01  OUTPUT-REC PIC X(2000).
   01  OUTPUT-LENGTH COMP PIC 9(4).
   01  DELIM PIC X.
   PROCEDURE DIVISION USING INPUT-REC INPUT-LENGTH
       OUTPUT-REC OUTPUT-LENGTH DELIM.
   BEGIN.
       IF INPUT-LENGTH = 0 OR > 2000
           MOVE 0 TO OUTPUT-LENGTH
           EXIT PROGRAM
       END-IF
       IF DELIM NOT = SPACE
           MOVE DELIM TO COMM
       ELSE
           MOVE "," TO COMM
       END-IF
       PERFORM CONVERT-RECORD
       SUBTRACT 1 FROM J GIVING OUTPUT-LENGTH
       EXIT PROGRAM
       .

   CONVERT-RECORD.
       MOVE 1 TO STATE I J FLD-START
       PERFORM CONVERT-RECORD-PROC
           UNTIL I > INPUT-LENGTH
       MOVE FLD-SEP TO OUTPUT-REC (J:1)
  *> FOR NO FIELD AFTER THE LAST DELIMITER
       IF INPUT-REC (I - 1:1) = COMM
           ADD 1 TO J
           MOVE FLD-SEP TO OUTPUT-REC (J:1)
       END-IF
       .

   CONVERT-RECORD-PROC.
  *> CSV-DT
       EVALUATE STATE
           ALSO I = FLD-START
           ALSO INPUT-REC (I:1)
           ALSO INPUT-REC (I + 1:1)
  *> RULE   1 DETERMINES IF FIELD BEGINS WITH QUOTE
       WHEN 1 ALSO TRUE ALSO QUOT ALSO ANY
           MOVE 2 TO STATE
           ADD 1 TO I
  *> RULE   2 SPECIAL CASE OF SPACE + APOSTROPHE AT FIELD START
       WHEN 1 ALSO TRUE ALSO SPACE ALSO APOS
           ADD 1 TO I
  *> RULE   3 COPIES ONE CHARACTER
       WHEN 1 ALSO ANY ALSO NOT COMM ALSO ANY
           MOVE INPUT-REC (I:1) TO OUTPUT-REC (J:1)
           ADD 1 TO I
           ADD 1 TO J
  *> RULE   4 ENDS A FIELD
       WHEN 1 ALSO ANY ALSO COMM ALSO ANY
           MOVE FLD-SEP TO OUTPUT-REC (J:1)
           ADD 1 TO I
           ADD 1 TO J
           MOVE I TO FLD-START
  *> RULE   5 FOR QUOTED FIELD DROPS INITAL QUOTE
       WHEN 2 ALSO ANY ALSO NOT QUOT ALSO ANY
           MOVE INPUT-REC (I:1) TO OUTPUT-REC (J:1)
           ADD 1 TO I
           ADD 1 TO J
  *> RULE   6 FOR QUOTED FIELD CONVERTS TWO QUOTED TO ONE
       WHEN 2 ALSO ANY ALSO QUOT ALSO QUOT
           MOVE QUOTE TO OUTPUT-REC (J:1)
           ADD 2 TO I
           ADD 1 TO J
  *> RULE   7 FOR QUOTED FIELD DROPS QUOTE BEFORE DELIMITER
       WHEN 2 ALSO ANY ALSO QUOT ALSO COMM
           MOVE FLD-SEP TO OUTPUT-REC (J:1)
           ADD 2 TO I
           ADD 1 TO J
           MOVE I TO FLD-START
           MOVE 1 TO STATE
  *> RULE   8 FOR QUOTED FIELD DROPS FINAL QUOTE OF LAST FIELD
       WHEN 2 ALSO ANY ALSO QUOT ALSO SPACE
           ADD 2 TO I
           ADD 1 TO J
           MOVE I TO FLD-START
           MOVE 1 TO STATE
       END-EVALUATE
       .

测试了以下 CSV 文件:

120,ABC,123,"12"" RULER","""ABC"", ""DEF"", ""GHI""", 'ABC',"123,456"
"""789""",,,,"""mno""",,

测试程序输出:

1: 120
2: ABC
3: 123
4: 12" RULER
5: "ABC", "DEF", "GHI"
6: 'ABC'
7: 123,456
1: "789"
2:
3:
4:
5: "mno"
6:
7:

【讨论】:

    猜你喜欢
    • 2017-08-08
    • 2014-07-27
    • 1970-01-01
    • 2013-07-30
    • 2011-12-25
    • 1970-01-01
    相关资源
    最近更新 更多