如何摆脱字符串中的尾随空格和嵌入空格?

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 给出相同的答案。对于多字节字符,它们没有。