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

时间:2015-08-11 07:42:58

标签: delimiter cobol

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 个答案:

答案 0 :(得分:8)

首先,值得赞扬的是,许多人会选择分隔两个空格而不关心可能造成的后果。请注意,如果数据后跟一个尾随空格,那么您也会得到意外的"输出。另请注意,OUTPUT-STRING的字段定义短一个字节,因为您要插入空格来分隔数据。如果两个字段都填满了数据,您将丢失SECOND-STRING的最后一个字节。

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

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

执行此操作的一种非常常见的方法是@ user4341206在其答案https://stackoverflow.com/a/31938039/1927206中的建议。

根据1985 COBOL标准,INSPECT可用于计算前导空格,但不能用于计算尾随空格。首先可以使用FUNCTION REVERSE将尾随空格转换为前导空格,以便INSPECT可以对它们进行计数。

一旦知道尾随空白的数量,就可以使用LENGTH OF特殊寄存器或FUNCTION LENGTH来确定固定长度字段的长度(两者都是(或者可以,取决于编译器)在编译时评估)。字段长度和尾随空白数之间的差异为您提供了数据的长度。

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

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

请注意,像AcuCOBOL(现在是Micro Focus&CO; 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和可变长度字段的解决方案不会失败",因为参考修改之外的编译器对零长度项感到满意。

然而,同样的"保护"应该使用两个原因:你要插入一个前导空格("分隔符");你可以明确地使用你的代码,这样人们就不必问自己"当第一个字段为空时会发生什么&#34 ;;你将节省处理费用。

通过这种方式,您的程序"描述您的数据"更好。随着"了解您的数据"作为精确程序设计的必要条件,程序描述数据的次数越多,创建佣金或遗漏错误就越困难,理解就越容易,更容易改变,就像发生的那样。数据结构发生了变化。

您还可以使用WITH POINTER选项查看STRING。首先,MOVE FIRST-STRING到OUTPUT-STRING(它也会将OUTPUT-STRING中未使用的字节清除到空间)。然后在length-field-you-define(对于插入空间)中添加一个,并在STRING中将其用于WITH POINTER。

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

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

不幸的是,并非所有COBOL编译器都能让这一切变得简单。 A"复杂的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代码非常简单:你在第一个字段中找到数据的长度;你只做三个简单的移动。

也许你可以尝试各自,以便更加了解未来情况的可能性。

答案 1 :(得分:7)

我不知道这是否会对你有所帮助,但如果你想删除第一个字符串的尾随空格,你可以在结束字符串之前这样做:

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

答案 2 :(得分:0)

我更喜欢使用内联执行来查找数据的长度,以去除尾随空格。最小长度1可以使string命令成功执行,即使数据全是空格。

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