如何消除字符串中的尾部和嵌入空格?

4
我正在编写一个程序,将国内和国际账号转换为IBAN号码。首先,我需要组成一个字符串:银行ID + 分行ID + 账户号码 + ISO国家代码,不包括这些字段可能存在的尾随空格。但并非每个帐户号码长度相同,有些帐户号码有分行标识符,而有些则没有,因此我将始终从这些字段中得到尾随空格。
我的工作存储大致如下:
      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 来统计前导空格。但我听说这是一种缓慢的方法。有人有什么想法吗?也许可以举个例子说明如何使用这个想法?
编辑: 我已被告知,基本字段可能包含嵌入式空格。

也许这可以回答你的问题:http://codereview.stackexchange.com/questions/69220/trim-functions-in-cobol - Hermann Klecker
任何一个基本字段都可以包含嵌入的空格吗? - Bill Woodger
谢谢你们抽出时间来帮助我。我刚刚更新了问题。 - Lena
2个回答

9
我现在发现你的数据中有空格。因此,迄今为止提供的答案都不可行。Gilbert的方法会将嵌入的空格“挤出”,我的方法会丢失每个字段第一个空格之后的所有数据。
然而,我认为如果您以任何方式生成“IBAN”,则无法嵌入空格。例如,在https://en.wikipedia.org/wiki/International_Bank_Account_Number#Structure中明确说明:
IBAN在电子传输时不应包含空格。当打印时,它由四个字符组成的组,并由单个空格分隔,最后一组长度可变。
如果您的源数据在字段级别处具有嵌入的空格,则需要将其反馈给决策层。假设您收到了正确的答案(字段级别没有嵌入的空格),那么两个现有答案都适用。您可以通过(逻辑上)将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。
每个源字段的数据复制将在遇到第一个空格时结束。如果一个字段完全为空格,则不会从中复制任何数据。 STRING 几乎肯定会导致运行时例程的执行,并且会有一些开销。Gilbert LeBlanc 的示例可能略微快一些,但是使用 STRING,编译器会自动处理所有字段的长度。由于您有 National 字段,请确保使用形式常量 SPACE(或 SPACES,它们是相同的),而不是您认为包含空格的文字值 " "。它确实包含空格,但它不包含 National 空格。
如果 STRING 的结果大于 34 个字符,则多余的字符将被静默截断。如果要处理这种情况,STRING 有一个 ON OVERFLOW 语句块,在其中指定在该情况下要执行的操作。如果使用 ON OVERFLOW,或者确实使用 NOT ON OVERFLOW,应使用 END-STRING 作为范围终止符号。句点也将终止 STRING 语句,但是当以这种方式使用时,它永远不能与 ON/NOT ON 一起在任何类型的条件语句中使用。
不要使用句点来终止范围。
COBOL 没有“字符串”。您无法摆脱固定长度字段中的尾随空格,除非数据填满该字段。当数据较短时,您的输出 IBAN 将始终包含尾随空格。
如果您实际上在字段级别上嵌入了空格:
首先,如果您想要“挤出”嵌入的空格,以便它们不出现在输出中,我无法想到比 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 可以计算前导空格,但不包括尾随空格(根据标准)。因此,您可以翻转字段中的字节,然后计算前导空格。
您有国家数据(PIC N)。与此有所不同的是,您需要计数的不是字节,而是由两个字节组成的字符。由于编译器知道您正在使用 PIC N 字段,所以只有一件事会让您犯错 - 特殊寄存器 LENGTH OF 计算字节,您需要使用 FUNCTION LENGTH 来计算字符。
国家数据是 UTF-16。这意味着每个字符的两个字节刚好是“ASCII”,当其中一个字节代表可显示字符时。这也不重要,因为在 z/OS 上运行,一个 EBCDIC 机器上,编译器将自动进行必要的转换以处理文字或字母数字数据项。
       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

如果可能或必要,需要再次处理溢出。

也可以使用普通的MOVE和引用修改,就像这个答案中所示:https://dev59.com/sY3da4cB1Zd3GeqP6_Rd#31941665,其问题与你的问题非常相似。

为什么要小心呢?回到之前链接的答案,理论上引用修改不能有零长度。

实际上,它可能会起作用。COBOL程序员似乎非常热衷于引用修改,以至于他们不会完全阅读有关它的内容,因此不用担心零长度不符合标准,并且不注意到它是非标准的,因为它“可以工作”。暂时的。直到编译器改变。

如果您使用的是Enterprise COBOL V5.2或更高版本(可能也适用于V5.1,我只是没有检查),则可以通过编译器选项来确保零长度引用修改按预期工作。

如果输出中可能存在嵌入的空格并且可以影响输出,则该答案中涵盖了一些其他实现任务的方法。对于National(国家字符集),请务必始终使用FUNCTION LENGTH(计算字符数),而不是LENGTH OF(计算字节数)。通常,LENGTH OF和FUNCTION LENGTH会给出相同的答案。对于多字节字符,它们不会。


如果你在"字符串"中间有空格,你可以使用这个回答来避免尾随的空格。链接 - Sarabadu
哇,非常感谢您提供的额外信息。这解释了很多问题!在Stack Overflow上是否可以选择“最佳答案”?如果可以,我该如何操作? - Lena
如果您查看答案左上角,您会看到一个“勾”的轮廓。单击它以“接受”帮助您最多的答案。这将为回答者提供15个声望和两个声望给您。您已经拥有足够的声望来投票支持任何帮助过您的答案(对于您的问题或任何其他问题)。对于“接受”,您不需要任何声望即可使用它。如果您查看每个页面顶部的帮助,您将看到“导览”和“帮助中心”,它们将告诉您所有操作方式。 - Bill Woodger

3

我无法验证这个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.

“交叉对话”和夸脱/品脱量杯。需要清除OUTPUT-IBAN以避免先前的数据。需要限制SUB2,使其不能超过34(如果发生这种情况,需要考虑如何处理)。另一个问题是PIC图像中的N。它们是“国家”的意思,每个字符由两个字节组成。因此,您需要在参考修改长度时使用2。LENGTH OF给出National的字节长度。您需要使用FUNCTION LENGTH (...) 获取字符长度,并针对“national”空格进行测试,这就是SPACE/SPACES所做的,但可能会让读者感到困惑。否则可以正常工作。 - Bill Woodger
Bill Woodger,如果我有你那么一点儿的知识,我就会很开心了。这足以说明我的水平,我甚至不知道如何根据这个新信息调整 Gilberts Cobol。 - Lena
此外,Gilbert,请原谅我的失礼。感谢您抽出时间回答问题。 - Lena

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接