Cobol 字符串由尾随空格分隔
Cobol String Delimited By Trailing SPACES
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 不包含两个空格,这会导致丢失它的一部分。
我不知道这是否对你有帮助,但如果你想删除第一个字符串的尾随空格,你可以在连接字符串之前做这样的事情:
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,)
首先,荣誉,因为许多人会使用由两个分隔的 space 并且根本不关心可能的后果。请注意,如果数据后跟一个尾随 space,您还会得到 "unexpected" 输出。另请注意,您的 OUTPUT-STRING 字段定义是一个字节短,因为您要插入 space 来分隔数据。由于两个字段都完全填满了数据,您将丢失 SECOND-STRING 的最后一个字节。
COBOL 是一种固定长度字段的语言(除非它们是可变的)。这意味着没有 "standard" 分隔符,因此任何字符或值都可以出现在字段中的任何位置。此外,源字段短于目标字段的默认填充字符是 space,这是一个完全正常的单词分隔符。
在您和许多类似的情况下,您需要知道字段的实际数据部分的长度(不包括尾随空格)。
@user4341206 在他们的回答中建议的一种非常常见的方法,。
在 1985 COBOL 标准下,INSPECT 可用于计算 leading spaces,但不能用于计算 trailing space秒。可以先使用 FUNCTION REVERSE
将尾随 space 变成前导 space,以便 INSPECT 可以计算它们。
一旦知道尾随空白的数量,就可以使用 LENGTH OF
特殊寄存器或 FUNCTION LENGTH
来确定固定长度字段的长度(两者都是(或者可以是,取决于编译器)在编译时评估)。字段长度与尾随空格数之间的差异就是数据的长度。
一旦你有了数据的长度,请记住它可能是空白的(取决于数据的可能性)并且它可能与字段的长度相同
请注意,如果您有大量数据,与从字段末尾开始的简单循环相比,您可能不希望反转字段并使用 INSPECT(可能是 运行-time 例程)计算尾随空格。
请注意,像 AcuCOBOL(现在是 Micro Focus 的 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 是默认值,但它确实让人类更清楚 reader。
您还可以在目标字段上使用带有引用修改的 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 : )
引用修改(在另一个答案中提到)存在一个特定问题,即您的长度字段不应为零。
The evaluation of length shall result in a positive nonzero integer.
在此上下文中的长度是引用修改表示法中 :
之后的第二项。在这种情况下,这意味着您定义的长度字段不能为零,如果 FIRST-STRING 完全为 space.
,则可以计算为零
潜在的问题在于:
MOVE FIRST-STRING TO OUTPUT-STRING
( 1 : length-field-you-define )
因此,根据您的数据(如果它可能包含空白),您必须 "protect" 反对。
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 : )
.
如果您使用长度为零的引用修改,结果是未定义的,尽管它可能 "work" 您的编译器。
具有 STRING 和可变长度字段的解决方案不会 "fail",因为引用修改之外的编译器对零长度项目很满意。
但是,出于两个原因,应该使用相同的 "protection":您将插入一个前导空格("separator");您将使您的代码明确,这样人们就不必问自己 "what happens when the first field is blank";您将节省处理费用。
这样你的程序也"describes your data"更好。加上"know your data"作为精确程序设计的必要条件,你的程序对数据的描述越多,越不容易产生错漏错,越容易理解,也越容易当数据结构发生变化时发生变化。
您还可以使用 WITH POINTER 选项查看 STRING。首先,将 FIRST-STRING 移动到 OUTPUT-STRING(这也会将 OUTPUT-STRING 中未使用的字节清除到 space)。然后将一个添加到您定义的长度字段(用于中间 space)并在 WITH POINTER 的 STRING 中使用它。
虽然这完全正确,但如果使用,这是一个评论的机会,因为很多经常使用 STRING 的人不知道 WITH POINTER 的用法,所以帮助他们。
另一种可能性是使用可变长度字段。
不幸的是,并不是所有的 COBOL 编译器都能让这变得简单。 "Complex 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。
也许你可以尝试每一种,以更加了解未来情况的可能性。
我更喜欢内联函数来查找数据的长度,去除尾随空格。最小长度为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...
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 不包含两个空格,这会导致丢失它的一部分。
我不知道这是否对你有帮助,但如果你想删除第一个字符串的尾随空格,你可以在连接字符串之前做这样的事情:
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,)
首先,荣誉,因为许多人会使用由两个分隔的 space 并且根本不关心可能的后果。请注意,如果数据后跟一个尾随 space,您还会得到 "unexpected" 输出。另请注意,您的 OUTPUT-STRING 字段定义是一个字节短,因为您要插入 space 来分隔数据。由于两个字段都完全填满了数据,您将丢失 SECOND-STRING 的最后一个字节。
COBOL 是一种固定长度字段的语言(除非它们是可变的)。这意味着没有 "standard" 分隔符,因此任何字符或值都可以出现在字段中的任何位置。此外,源字段短于目标字段的默认填充字符是 space,这是一个完全正常的单词分隔符。
在您和许多类似的情况下,您需要知道字段的实际数据部分的长度(不包括尾随空格)。
@user4341206 在他们的回答中建议的一种非常常见的方法,
在 1985 COBOL 标准下,INSPECT 可用于计算 leading spaces,但不能用于计算 trailing space秒。可以先使用 FUNCTION REVERSE
将尾随 space 变成前导 space,以便 INSPECT 可以计算它们。
一旦知道尾随空白的数量,就可以使用 LENGTH OF
特殊寄存器或 FUNCTION LENGTH
来确定固定长度字段的长度(两者都是(或者可以是,取决于编译器)在编译时评估)。字段长度与尾随空格数之间的差异就是数据的长度。
一旦你有了数据的长度,请记住它可能是空白的(取决于数据的可能性)并且它可能与字段的长度相同
请注意,如果您有大量数据,与从字段末尾开始的简单循环相比,您可能不希望反转字段并使用 INSPECT(可能是 运行-time 例程)计算尾随空格。
请注意,像 AcuCOBOL(现在是 Micro Focus 的 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 是默认值,但它确实让人类更清楚 reader。
您还可以在目标字段上使用带有引用修改的 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 : )
引用修改(在另一个答案中提到)存在一个特定问题,即您的长度字段不应为零。
The evaluation of length shall result in a positive nonzero integer.
在此上下文中的长度是引用修改表示法中 :
之后的第二项。在这种情况下,这意味着您定义的长度字段不能为零,如果 FIRST-STRING 完全为 space.
潜在的问题在于:
MOVE FIRST-STRING TO OUTPUT-STRING
( 1 : length-field-you-define )
因此,根据您的数据(如果它可能包含空白),您必须 "protect" 反对。
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 : )
.
如果您使用长度为零的引用修改,结果是未定义的,尽管它可能 "work" 您的编译器。
具有 STRING 和可变长度字段的解决方案不会 "fail",因为引用修改之外的编译器对零长度项目很满意。
但是,出于两个原因,应该使用相同的 "protection":您将插入一个前导空格("separator");您将使您的代码明确,这样人们就不必问自己 "what happens when the first field is blank";您将节省处理费用。
这样你的程序也"describes your data"更好。加上"know your data"作为精确程序设计的必要条件,你的程序对数据的描述越多,越不容易产生错漏错,越容易理解,也越容易当数据结构发生变化时发生变化。
您还可以使用 WITH POINTER 选项查看 STRING。首先,将 FIRST-STRING 移动到 OUTPUT-STRING(这也会将 OUTPUT-STRING 中未使用的字节清除到 space)。然后将一个添加到您定义的长度字段(用于中间 space)并在 WITH POINTER 的 STRING 中使用它。
虽然这完全正确,但如果使用,这是一个评论的机会,因为很多经常使用 STRING 的人不知道 WITH POINTER 的用法,所以帮助他们。
另一种可能性是使用可变长度字段。
不幸的是,并不是所有的 COBOL 编译器都能让这变得简单。 "Complex 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。
也许你可以尝试每一种,以更加了解未来情况的可能性。
我更喜欢内联函数来查找数据的长度,去除尾随空格。最小长度为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...