如何摆脱字符串中的尾随空格和嵌入空格?
How do I get rid of trailing and embedded spaces in a string?
我正在编写一个程序,将国内和国际帐号转换为 IBAN 号码。首先,我需要形成一个字符串:Bank ID + Branch ID + Account Number + ISO Country Code,不带这些字段中可能存在的尾随空格。但并不是每个帐号都有相同的长度,一些帐号有分支标识符,而另一些则没有,所以我总是以这些字段的尾随空格结束。
我的工作存储看起来像这样:
01 Input-IBAN.
05 BANK-ID PIC N(10) VALUE "LOYD".
05 BRANCH-ID PIC N(10) VALUE " ".
05 ACCOUNT-NR PIC N(28) VALUE "012345678912 ".
05 COUNTRY-CODE PIC N(02) VALUE "GB".
01 Output-IBAN PIC N(34).
我已经为这个例子放了一些值;实际上,这取决于输入。分支代码是可选的,因此我在示例中将其留空。
我基本上想从这个输入串起来:
"LOYD 012345678912 GB"
对此:
"LOYD012345678912GB"
有谁知道一种不会导致性能问题的方法吗?我想过使用 FUNCTION REVERSE
然后使用 INSPECT
来计算前导空格。但我听说这是一种缓慢的方法。有人有什么想法吗?也许还有一个关于如何使用上述想法的例子?
编辑:
我被告知基本字段可能包含嵌入的空间。
我无法验证这个 COBOL。让我知道这是否有效。
77 SUB1 PIC S9(4) COMP.
77 SUB2 PIC S9(4) COMP.
MOVE 1 TO SUB2
PERFORM VARYING SUB1 FROM 1 BY 1
UNTIL SUB1 > LENGTH OF INPUT-IBAN
IF INPUT-IBAN(SUB1:1) IS NOT EQUAL TO SPACE
MOVE INPUT-IBAN(SUB1:1) TO OUTPUT-IBAN(SUB2:1)
ADD +1 TO SUB2
END-IF
END-PERFORM.
我现在看到您在数据中嵌入了空白。那么,到目前为止,您没有任何答案。 Gilbert 的 "squeezes out" 嵌入的空白,我的会丢失每个字段中第一个空白之后的所有数据。
但是,要指出的是,如果您以任何方式生成 "IBAN",我真的不相信您可以嵌入空白。例如,https://en.wikipedia.org/wiki/International_Bank_Account_Number#Structure,
具体来说:
The IBAN should not contain spaces when transmitted electronically.
When printed it is expressed in groups of four characters separated by
a single space, the last group being of variable length
如果您的源数据在字段级别嵌入了空白,那么您需要参考该备份行来决定要做什么。假设您收到了正确的答案(字段级别没有嵌入空白),那么两个现有答案都会返回 table。您通过(逻辑上)将 LENGTH OF 更改为 FUNCTION LENGTH 并处理任何溢出输出的可能性来修改 Gilbert。
对于 STRING,您必须再次处理输出溢出的可能性。
原始答案基于没有嵌入空格的假设。
我假设您在构成结构的基本项目中没有嵌入空格,因为它们源自不包含嵌入空格的标准值。
MOVE SPACE TO OUTPUT-IBAN
STRING BANK-ID
BRANCH-ID
ACCOUNT-NR
COUNTRY-CODE
DELIMITED BY SPACE
INTO OUTPUT-IBAN
STRING
仅复制值,直到 运行 没有数据可复制,因此有必要在 STRING 之前清除 OUTPUT-IBAN。
每个源字段中的数据复制将在每个源字段中遇到第一个 SPACE 时结束。如果一个字段完全是 space,则不会从中复制任何数据。
STRING 几乎肯定会导致执行 运行-time 例程,并且会有一些开销。 Gilbert LeBlanc 的示例可能稍微快一些,但使用 STRING 时,编译器会自动处理所有字段的所有长度。因为您有国家字段,请确保您使用的是比喻常数 SPACE(或 SPACES,它们是相同的)而不是您认为包含 space " "
的字面值.有,但不包含国家 space.
如果 STRING 的结果大于 34 个字符,超出的字符将被悄悄处理 运行。如果你想处理这个问题,STRING 有一个 ON OVERFLOW
短语,你可以在其中指定在这种情况下你想做什么。如果使用 ON OVERFLOW,或者确实使用 NOT ON OVERFLOW
,您应该使用 END-STRING
范围终止符。 full-stop/period 也会终止 STRING 语句,但是当这样使用时,它永远不能在任何类型的条件语句中使用 ON/NOT ON。
不要使用 full-stops/periods 来终止作用域。
COBOL 没有 "strings"。您不能去掉固定长度字段中的尾随 space,除非数据填满该字段。当数据较短时,您的输出 IBAN 将始终包含尾随 spaces。
如果您实际上要在字段级别嵌入空白:
首先,如果您想 "squeeze out" 嵌入空白,这样它们就不会出现在输出中,我想不出比 Gilbert 更简单的方法(使用 COBOL)。
否则,如果要保留嵌入的空白,除了计算尾随空白以便计算每个字段中实际数据的长度外,您别无选择。
COBOL 实现确实有语言扩展。不清楚您使用的是哪种 COBOL 编译器。如果它恰好是 AcuCOBOL(现在来自 Micro Focus),那么 INSPECT 支持 TRAILING,您可以用这种方式计算尾随空白。 GnuCOBOL 还支持 INSPECT 上的 TRAILING,此外还有一个有用的内在函数 TRIM,您可以使用它在 STRING 语句中执行您想要的操作(修剪尾随空白)。
move space to your-output-field
string function
trim
( your-first-national-source
trailing )
function
trim
( your-second-national-source
trailing )
function
trim
( your-third-national-source
trailing )
...
delimited by size
into your-output-field
请注意,除了您定义中的 PIC N 之外,代码与使用字母数字字段时相同。
但是,对于标准 COBOL 85 代码...
您提到使用 FUNCTION REVERSE,然后使用 INSPECT。 INSPECT 可以计算前导 spaces,但不能计算尾随 spaces。所以可以将一个字段中的字节取反,然后统计前导的spaces.
您有国家数据 (PIC N)。与此不同的是,您需要计算的不是字节,而是由两个字节组成的字符。由于编译器知道您正在使用 PIC N 字段,因此只有一件事会让您绊倒 - 特殊寄存器 LENGTH OF 计算字节数,您需要 FUNCTION LENGTH 来计算字符数。
国家数据为UTF-16。这恰好意味着每个字符的两个字节恰好是 "ASCII",其中一个字节恰好代表一个可显示的字符。这也没关系,运行 在 EBCDIC 机器 z/OS 上运行,因为编译器会自动对文字或字母数字数据项进行必要的转换。
MOVE ZERO TO a-count-for-each-field
INSPECT FUNCTION
REVERSE
( each-source-field )
TALLYING a-count-for-each-field
FOR LEADING SPACE
对每个字段执行其中一项后,您可以使用引用修改。
如何为此使用引用修改?
首先,你要小心。其次你没有。
其次第一:
MOVE SPACE TO output-field
STRING field-1 ( 1 : length-1 )
field-2 ( 1 : length-2 )
DELIMITED BY SIZE
INTO output-field
如果possible/necessary再次处理溢出。
也可以使用简单的 MOVE 和引用修改,如在这个答案中,,其问题与您的问题几乎相同。
为什么要小心?同样,根据之前链接的答案,理论上参考修改的长度不能为零。
在实践中,它可能会起作用。 COBOL 程序员通常似乎非常热衷于引用修改,以至于他们懒得去完整地阅读它,所以不要担心零长度不是标准的,也不要注意到它是非标准的,因为它 "works"。目前。直到编译器改变。
如果您使用的是 Enterprise COBOL V5.2 或更高版本(也可能是 V5.1,我只是没有检查),那么您可以通过编译器选项确定零长度参考修改按预期工作。
如果嵌入的空白可以存在并且在输出中很重要,那么完成任务的其他一些方法也包含在该答案中。对于 National,请始终注意使用 FUNCTION LENGTH(计算字符数),而不是 LENGTH OF(计算字节数)。通常 LENGTH OF 和 FUNCTION LENGTH 给出相同的答案。对于多字节字符,它们没有。
我正在编写一个程序,将国内和国际帐号转换为 IBAN 号码。首先,我需要形成一个字符串:Bank ID + Branch ID + Account Number + ISO Country Code,不带这些字段中可能存在的尾随空格。但并不是每个帐号都有相同的长度,一些帐号有分支标识符,而另一些则没有,所以我总是以这些字段的尾随空格结束。
我的工作存储看起来像这样:
01 Input-IBAN.
05 BANK-ID PIC N(10) VALUE "LOYD".
05 BRANCH-ID PIC N(10) VALUE " ".
05 ACCOUNT-NR PIC N(28) VALUE "012345678912 ".
05 COUNTRY-CODE PIC N(02) VALUE "GB".
01 Output-IBAN PIC N(34).
我已经为这个例子放了一些值;实际上,这取决于输入。分支代码是可选的,因此我在示例中将其留空。
我基本上想从这个输入串起来:
"LOYD 012345678912 GB"
对此:
"LOYD012345678912GB"
有谁知道一种不会导致性能问题的方法吗?我想过使用 FUNCTION REVERSE
然后使用 INSPECT
来计算前导空格。但我听说这是一种缓慢的方法。有人有什么想法吗?也许还有一个关于如何使用上述想法的例子?
编辑: 我被告知基本字段可能包含嵌入的空间。
我无法验证这个 COBOL。让我知道这是否有效。
77 SUB1 PIC S9(4) COMP.
77 SUB2 PIC S9(4) COMP.
MOVE 1 TO SUB2
PERFORM VARYING SUB1 FROM 1 BY 1
UNTIL SUB1 > LENGTH OF INPUT-IBAN
IF INPUT-IBAN(SUB1:1) IS NOT EQUAL TO SPACE
MOVE INPUT-IBAN(SUB1:1) TO OUTPUT-IBAN(SUB2:1)
ADD +1 TO SUB2
END-IF
END-PERFORM.
我现在看到您在数据中嵌入了空白。那么,到目前为止,您没有任何答案。 Gilbert 的 "squeezes out" 嵌入的空白,我的会丢失每个字段中第一个空白之后的所有数据。
但是,要指出的是,如果您以任何方式生成 "IBAN",我真的不相信您可以嵌入空白。例如,https://en.wikipedia.org/wiki/International_Bank_Account_Number#Structure, 具体来说:
The IBAN should not contain spaces when transmitted electronically. When printed it is expressed in groups of four characters separated by a single space, the last group being of variable length
如果您的源数据在字段级别嵌入了空白,那么您需要参考该备份行来决定要做什么。假设您收到了正确的答案(字段级别没有嵌入空白),那么两个现有答案都会返回 table。您通过(逻辑上)将 LENGTH OF 更改为 FUNCTION LENGTH 并处理任何溢出输出的可能性来修改 Gilbert。
对于 STRING,您必须再次处理输出溢出的可能性。
原始答案基于没有嵌入空格的假设。
我假设您在构成结构的基本项目中没有嵌入空格,因为它们源自不包含嵌入空格的标准值。
MOVE SPACE TO OUTPUT-IBAN
STRING BANK-ID
BRANCH-ID
ACCOUNT-NR
COUNTRY-CODE
DELIMITED BY SPACE
INTO OUTPUT-IBAN
STRING
仅复制值,直到 运行 没有数据可复制,因此有必要在 STRING 之前清除 OUTPUT-IBAN。
每个源字段中的数据复制将在每个源字段中遇到第一个 SPACE 时结束。如果一个字段完全是 space,则不会从中复制任何数据。
STRING 几乎肯定会导致执行 运行-time 例程,并且会有一些开销。 Gilbert LeBlanc 的示例可能稍微快一些,但使用 STRING 时,编译器会自动处理所有字段的所有长度。因为您有国家字段,请确保您使用的是比喻常数 SPACE(或 SPACES,它们是相同的)而不是您认为包含 space " "
的字面值.有,但不包含国家 space.
如果 STRING 的结果大于 34 个字符,超出的字符将被悄悄处理 运行。如果你想处理这个问题,STRING 有一个 ON OVERFLOW
短语,你可以在其中指定在这种情况下你想做什么。如果使用 ON OVERFLOW,或者确实使用 NOT ON OVERFLOW
,您应该使用 END-STRING
范围终止符。 full-stop/period 也会终止 STRING 语句,但是当这样使用时,它永远不能在任何类型的条件语句中使用 ON/NOT ON。
不要使用 full-stops/periods 来终止作用域。
COBOL 没有 "strings"。您不能去掉固定长度字段中的尾随 space,除非数据填满该字段。当数据较短时,您的输出 IBAN 将始终包含尾随 spaces。
如果您实际上要在字段级别嵌入空白:
首先,如果您想 "squeeze out" 嵌入空白,这样它们就不会出现在输出中,我想不出比 Gilbert 更简单的方法(使用 COBOL)。
否则,如果要保留嵌入的空白,除了计算尾随空白以便计算每个字段中实际数据的长度外,您别无选择。
COBOL 实现确实有语言扩展。不清楚您使用的是哪种 COBOL 编译器。如果它恰好是 AcuCOBOL(现在来自 Micro Focus),那么 INSPECT 支持 TRAILING,您可以用这种方式计算尾随空白。 GnuCOBOL 还支持 INSPECT 上的 TRAILING,此外还有一个有用的内在函数 TRIM,您可以使用它在 STRING 语句中执行您想要的操作(修剪尾随空白)。
move space to your-output-field
string function
trim
( your-first-national-source
trailing )
function
trim
( your-second-national-source
trailing )
function
trim
( your-third-national-source
trailing )
...
delimited by size
into your-output-field
请注意,除了您定义中的 PIC N 之外,代码与使用字母数字字段时相同。
但是,对于标准 COBOL 85 代码...
您提到使用 FUNCTION REVERSE,然后使用 INSPECT。 INSPECT 可以计算前导 spaces,但不能计算尾随 spaces。所以可以将一个字段中的字节取反,然后统计前导的spaces.
您有国家数据 (PIC N)。与此不同的是,您需要计算的不是字节,而是由两个字节组成的字符。由于编译器知道您正在使用 PIC N 字段,因此只有一件事会让您绊倒 - 特殊寄存器 LENGTH OF 计算字节数,您需要 FUNCTION LENGTH 来计算字符数。
国家数据为UTF-16。这恰好意味着每个字符的两个字节恰好是 "ASCII",其中一个字节恰好代表一个可显示的字符。这也没关系,运行 在 EBCDIC 机器 z/OS 上运行,因为编译器会自动对文字或字母数字数据项进行必要的转换。
MOVE ZERO TO a-count-for-each-field
INSPECT FUNCTION
REVERSE
( each-source-field )
TALLYING a-count-for-each-field
FOR LEADING SPACE
对每个字段执行其中一项后,您可以使用引用修改。
如何为此使用引用修改?
首先,你要小心。其次你没有。
其次第一:
MOVE SPACE TO output-field
STRING field-1 ( 1 : length-1 )
field-2 ( 1 : length-2 )
DELIMITED BY SIZE
INTO output-field
如果possible/necessary再次处理溢出。
也可以使用简单的 MOVE 和引用修改,如在这个答案中,
为什么要小心?同样,根据之前链接的答案,理论上参考修改的长度不能为零。
在实践中,它可能会起作用。 COBOL 程序员通常似乎非常热衷于引用修改,以至于他们懒得去完整地阅读它,所以不要担心零长度不是标准的,也不要注意到它是非标准的,因为它 "works"。目前。直到编译器改变。
如果您使用的是 Enterprise COBOL V5.2 或更高版本(也可能是 V5.1,我只是没有检查),那么您可以通过编译器选项确定零长度参考修改按预期工作。
如果嵌入的空白可以存在并且在输出中很重要,那么完成任务的其他一些方法也包含在该答案中。对于 National,请始终注意使用 FUNCTION LENGTH(计算字符数),而不是 LENGTH OF(计算字节数)。通常 LENGTH OF 和 FUNCTION LENGTH 给出相同的答案。对于多字节字符,它们没有。