代码之家  ›  专栏  ›  技术社区  ›  raz_user

由尾随空格分隔的Cobol字符串

  •  4
  • raz_user  · 技术社区  · 9 年前
    WORKING-STORAGE.
        FIRST-STRING    PIC X(15) VALUE SPACES.
        SECOND-STRING     PIC X(15) VALUE SPACES.
        OUTPUT-STRING     PIC X(31) VALUE SPACES.
    

    如果 FIRST-NAME = 'JON SNOW, ' and LAST-NAME = 'KNOWS NOTHING. ' ,如何获取:

    我想得到:

    OUTPUT-STRING = 'JON SNOW, KNOWS NOTHING.         '
    

    当我尝试:

    String FIRST-STRING DELIMITED BY SPACES
           ' ' DELIMITED BY SIZE
           SECOND-STRING DELIMITED BY SIZE
           INTO OUTPUT-STRING
    

    我明白了 'JON KNOWS NOTHING. '

    当我尝试:

    String FIRST-STRING DELIMITED BY SIZE
           SECOND-STRING DELIMITED BY SIZE
           INTO OUTPUT-STRING
    

    我明白了 'JON SNOW, KNOWS NOTHING. '

    我找到了一个调整,包括 String FIRST-STRING DELIMITED BY ' ' (两个空格) 但不能保证我的FIRST-STRING不包含两个空格,这将导致丢失部分空格。

    3 回复  |  直到 9 年前
        1
  •  10
  •   Community Ian Goodfellow    7 年前

    首先,荣誉,因为许多人会用两个空格来分隔,而根本不担心可能的后果。注意,如果数据后面只有一个尾随空格,那么也会得到“意外”的输出。还要注意,OUTPUT-STRING的字段定义短了一个字节,因为您插入了一个空格来分隔数据。如果两个字段都完全填充了数据,则将丢失SECOND-STRING的最后一个字节。

    COBOL是一种固定长度字段的语言(可变字段除外)。这意味着没有“标准”分隔符,因此任何字符或值都可以出现在字段中的任何位置。此外,源字段比目标字段短的默认填充字符是空格,这是一个非常正常的单词分隔符。

    在您和许多类似的情况下,您需要知道字段的实际数据部分的长度(不包括尾随空格)。

    一种非常常见的方法是@user4341206在他们的回答中建议的, https://stackoverflow.com/a/31938039/1927206 .

    根据1985年COBOL标准,INSPECT可用于计数 主要的 空格,但不能用于计数 拖尾的,拖尾的 空间。 FUNCTION REVERSE 可以首先将尾随空格转换为前导空格,以便INSPECT可以对其进行计数。

    一旦知道尾随空格的数量,就可以使用 LENGTH OF 特殊寄存器或 FUNCTION LENGTH 以确定固定长度字段的长度(这两个字段都是(或可以,取决于编译器)在编译时求值的)。字段长度和尾随空格数之间的差异为数据长度。

    一旦您确定了数据的长度,并记住它可能是空白的(取决于数据的可能性),并且它可能与字段的长度相同

    请注意,如果您有大量数据,您可能不希望反转字段并使用INSPECT(可能是一个运行时例程),而不是从字段末尾开始的简单循环来计算尾随空格。

    注意,像AcuCOBOL(现在是MicroFocus COBOL产品的一部分)这样的编译器有一个语言扩展,它提供TRAILING作为INSPECT的选项。注意,即使是2014 COBOL标准也没有TRAILING作为INSPECT的选项。

    无论哪种方式,都要根据数据的长度。某种程度上。

    可以在STRING语句中使用引用修改:

    String FIRST-STRING ( 1 : length-field-you-define ) DELIMITED BY SIZE
           ' ' DELIMITED BY SIZE
           SECOND-STRING DELIMITED BY SIZE
       INTO OUTPUT-STRING
    

    注意,您应该能够删除BY SIZE,因为SIZE是默认值,但它确实使读者更清楚。

    您也可以在目标字段上使用带有引用修改的MOVE:

    MOVE FIRST-STRING            TO OUTPUT-STRING  
                                     ( 1 : length-field-you-define )
    MOVE SPACE                   TO OUTPUT-STRING  
                                     ( length-field-you-define + 1 : 1 )
    MOVE SECOND-STRING           TO OUTPUT-STRING  
                                     ( length-field-you-define + 2 :  )
    

    引用修改有一个特殊的问题(在另一个答案中提到),即长度字段不应为零。

    长度的计算结果应为正非零整数。

    本文中的长度是第二项,在 : ,在参考修改符号中。在这种情况下,这意味着您定义的长度字段不能为零,如果FIRST-STRING完全是空格,则可以计算为零。

    潜在的问题在于:

    MOVE FIRST-STRING            TO OUTPUT-STRING  
                                     ( 1 : length-field-you-define )
    

    因此,根据您的数据(如果它可能包含空格),您必须“保护”它。

        IF FIRST-STRING EQUAL TO SPACE
            PERFORM                  COPY-SECOND-STRING-ONLY
        ELSE
            PERFORM                  CONCATENATE-FIRST-AND-SECOND
        END-IF
        ...
    COPY-SECOND-STRING-ONLY.
        MOVE SECOND-STRING           TO OUTPUT-STRING
        .
    CONCATENATE-FIRST-AND-SECOND.
        calculate length
        MOVE FIRST-STRING            TO OUTPUT-STRING  
                                        ( 1 : length-field-you-define )
        MOVE SPACE                   TO OUTPUT-STRING  
                                        ( length-field-you-define + 1 : 1 )
        MOVE SECOND-STRING           TO OUTPUT-STRING  
                                        ( length-field-you-define + 2 :  )
        .
    

    如果使用长度为零的引用修改,则结果是未定义的,尽管它可以在编译器中“工作”。

    STRING和可变长度字段的解决方案不会“失败”,因为编译器在引用修改之外对零长度项很满意。

    然而,出于两个原因,应该使用相同的“保护”:您将插入前导空格(“分隔符”);您将使代码显式,这样人们就不必问自己“当第一个字段为空时会发生什么”;您将节省处理时间。

    这样,您的程序也可以更好地“描述您的数据”。除了“了解您的数据”作为准确程序设计的必要条件外,您的程序对数据的描述越多,就越难产生委托或遗漏的错误,就越容易理解,当数据结构发生变化时,也就越容易改变。

    您还可以使用WITH POINTER选项查看STRING。首先,将FIRST-STRING移动到OUTPUT-STRING(这也会将OUTPUT-STRING中未使用的字节清除到空格)。然后在您定义的长度字段中添加一个(用于中间空格),并在STRING中使用该字段作为WITH POINTER。

    虽然这是完全有效的,但如果使用,这是一个发表评论的机会,因为许多经常使用STRING的人不知道WITH POINTER的用法,所以请帮助他们。

    另一种可能性是使用可变长度字段。

    不幸的是,并不是所有的COBOL编译器都能做到这一点。“复杂的ODO”是非标准的,但它是该语言的IBM扩展。

    LINKAGE SECTION.
    01  L-MAPPING-OF-OUTPUT-STRING.
        05  L-MOOS-FIRST-STRING.
            10  FILLER OCCURS 0 TO 15 TIMES
                DEPENDING ON length-field-you-define.
                15  FILLER                          PIC X.
        05  L-MOOS-SEPARATOR-SPACE                  PIC X.
        05  L-MOOS-SECOND-STRING                    PIC X(15).
    
        ...
        SET ADDRESS OF L-MAPPING-OF-OUTPUT-STRING
                                 TO ADDRESS OF 
                                     OUTPUT-STRING  
        MOVE FIRST-STRING        TO L-MOOS-FIRST-STRING
        MOVE SPACE               TO L-MOOS-SEPARATOR-SPACE
        MOVE SECOND-STRING       TO L-MOOS-SECOND-STRING
    

    如果您有大量数据,最快的方法是仅参考修改建议。我对引用修改的看法是,它倾向于混淆,因为人们倾向于以混淆(和不必要)的方式使用它。

    我倾向于最后一种,其中PROCEDURE DIVISION代码非常简单:您可以在第一个字段中找到数据的长度;你只做三个简单的动作。

    也许你可以尝试每一种方法,以更加了解未来情况的可能性。

        2
  •  7
  •   user4341206    9 年前

    我不知道这是否对您有帮助,但如果您想删除第一个字符串的尾随空格,可以在插入字符串之前执行以下操作:

    INSPECT FUNCTION REVERSE(FIRST-STRING) TALLYING W-SPACES FOR LEADING SPACES
    
    COMPUTE W-FIRST-STRING-LEN = LENGTH OF FIRST-STRING - W-SPACES
    

    FIRST-STRING(1:W-FIRST-STRING-LEN) 然后包含没有尾随空格的第一个字符串(JOHN SNOW,)

        3
  •  0
  •   Joe    4 年前

    我更喜欢内联执行来查找数据的长度,去掉尾部空格。最小长度1将允许字符串命令成功,即使数据是所有空格。

    PERFORM VARYING FIELD-LEN
       FROM LENGTH OF SEARCH-FIELD BY -1
      UNTIL FIELD-LEN = 1
         OR SEARCH-FIELD(FIELD-LEN:1) NOT = SPACE
    END-PERFORM.
    
    STRING SEARCH-FIELD(1:FIELD-LEN) DELIMITED BY SIZE
           etc...