首先,要赞赏一下你,因为许多人会用两个空格作为分隔符,并不会对可能的后果感到担忧。请注意,如果数据后跟一个尾随空格,则还会产生“意外”的输出。另请注意,OUTPUT-STRING的字段定义短了一个字节,因为您插入了一个空格来分隔数据。如果这两个字段都完全填满了数据,则将失去SECOND-STRING的最后一个字节。
COBOL是固定长度字段的语言(除非它们是可变的)。这意味着没有“标准”分隔符,因此任何字符或值都可以出现在字段的任何位置。此外,源字段比目标字段短时的默认填充字符是空格,这是单词的完全正常分隔符。
在您以及许多类似情况中,您需要知道字段实际数据部分的长度(不包括尾随空格)。
做到这一点的一种非常常见的方法是由@user4341206在他们的答案中提出的建议,https://dev59.com/sY3da4cB1Zd3GeqP6_Rd#31938039。
在1985年的COBOL标准下,INSPECT可以用于计算前导空格,但不能用于计算尾随空格。可以先使用FUNCTION REVERSE
将尾随空格转换为前导空格,以便INSPECT可以对其进行计数。
一旦您知道了尾随空格的数量,就可以使用LENGTH OF
特殊寄存器或FUNCTION LENGTH
来确定固定长度字段的长度(取决于编译器可能会评估)。字段长度与尾随空格数之间的差异给出了数据的长度。
一旦您知道了数据的长度,并牢记它可能为空(取决于数据可能性)并且长度可能与字段相同
请注意,如果有大量数据,您可能不想反转字段并使用INSPECT(与从字段末尾循环以计算尾随空格相比,这可能是运行时例程)。
请注意,像AcuCOBOL(现在是Micro Focus的COBOL产品的一部分)这样的编译器具有一种语言扩展,可为INSPECT提供TRAILING选项。请注意,即使是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 : )
.
如果使用长度为零的引用修改器,则结果未定义,尽管它可能会在您的编译器中“工作”。
对于字符串和可变长度字段的解决方案不会“失败”,因为除了引用修改器之外的编译器都可以接受长度为零的项。
然而,出于两个原因应该采用同样的“保护”措施:首先要插入一个前导空格(“分隔符”);其次,要使代码明确,这样人们就不必自问“第一个字段为空时会发生什么”;还可以节省处理时间。这样也可以更好地“描述数据”。与准确的程序设计所需的“了解数据”一样,您的程序描述数据越多,就越难出现遗漏或差错,并且更易于理解和更易于在数据结构更改时进行更改。
您还可以查看使用 WITH POINTER 选项的 STRING。首先,将 FIRST-STRING 移动到 OUTPUT-STRING(这也会将 OUTPUT-STRING 中未使用的字节清除为空格)。然后,在您定义的长度字段中加一(表示介于两者之间的空格),并在带有 POINTER 的 STRING 中使用它。
虽然这是完全有效的,但如果使用它,应该加上注释,因为许多经常使用 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代码非常简单:您可以在第一个字段中找到数据的长度;只需进行三个普通的MOVE操作即可。
也许您可以尝试每一种方法,以便更加了解未来情况的可能性。