我正在编写一个程序,将国内和国际帐号转换为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
来计算前导空格。但我听说这是一个缓慢的方法。有没有人有任何想法?也许是一个如何使用这个想法的例子?
修改 我被告知基本字段可能包含嵌入空格。
答案 0 :(得分:8)
我现在看到你在数据中嵌入了空格。到目前为止,你的答案都没有。吉尔伯特"挤出"嵌入的空白,我的每个字段中的第一个空白后会丢失任何数据。
然而,只是要指出,如果您以任何方式产生" IBAN",我真的不相信您可以嵌入空白。例如,https://en.wikipedia.org/wiki/International_Bank_Account_Number#Structure, 具体来说:
IBAN在电子传输时不应包含空格。 打印时,它以四个字符组分隔 一个空格,最后一组是可变长度
如果您的源数据嵌入了空白,则在现场级别,您需要引用该行备份,以决定该怎么做。假设您收到正确的答案(在现场级别没有嵌入的空白),那么现有的答案都会回到桌面上。你通过(逻辑上)将LENGTH OF改为FUNCTION LENGTH并处理任何溢出输出的可能性来修改Gilbert's。
使用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时,将复制来自每个源字段的数据。如果某个字段完全是空格,则不会从中复制任何数据。
STRING几乎肯定会导致执行运行时例程,并且会有一些开销。 Gilbert LeBlanc的例子可能稍快一点,但是使用STRING,编译器会自动处理所有字段的所有长度。因为您有National字段,所以请确保使用图形常量SPACE(或SPACES,它们是相同的)而不是您认为包含空格" "
的字面值。它确实如此,但它并没有包含国家空间。
如果STRING的结果大于34个字符,则会多余地截断多余的字符。如果你想处理它,STRING有一个ON OVERFLOW
短语,你可以在那里指定你想做的事情。如果使用ON OVERFLOW,或者确实NOT ON OVERFLOW
,您应该使用END-STRING
范围终止符。一个句号/句号也会终止STRING语句,但是当它被这样使用时,它永远不能在ON / NOT ON的情况下在任何类型的条件语句中使用。
不要使用句号/句号来终止范围。
COBOL没有"字符串"。除非数据填充字段,否则无法删除固定长度字段中的尾随空格。当数据很短时,您的输出IBAN将始终包含尾随空格。
如果你真的在现场级别有嵌入式空白:
首先,如果你想"挤出"嵌入式空白使得它们不会出现在输出中,我无法想到比吉尔伯特更简单的方法(使用COBOL)。
否则,如果要保留嵌入的空格,除了计算尾随空白以外,您没有其他合理的选择,这样您就可以计算每个字段中实际数据的长度。
COBOL实现确实有语言扩展。目前还不清楚您使用的是哪种COBOL编译器。如果恰好是AcuCOBOL(现在来自Micro Focus),那么INSPECT支持TRAILING,你可以用这种方式计算尾随空白。 GnuCOBOL还支持INSPECT上的TRAILING,另外还有一个有用的内在功能TRIM,您可以使用它来完成您想要的操作(修剪尾随空白)。
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://stackoverflow.com/a/31941665/1927206,其问题接近你的问题的副本。
你为什么要小心?同样,从之前链接的答案中,理论上参考修改的长度不能为零。
在实践中,它可能会起作用。 COBOL程序员通常似乎非常热衷于参考修改,以至于他们不必完全阅读它,所以不要担心零长度不是标准的,并且没有注意到它是非标准的,因为它"工作"。目前。直到编译器发生变化。
如果您使用的是Enterprise COBOL V5.2或更高版本(也可能是V5.1,我还没有检查过),那么您可以通过编译器选项确定是否需要零长度引用修改按预期工作。
如果嵌入的空白可以存在并且在输出中可能很重要,那么实现任务的其他一些方法也包含在该答案中。使用National,只需要使用FUNCTION LENGTH(计算字符数),而不是LENGTH OF(计算字节数)。通常LENGTH OF和FUNCTION LENGTH给出相同的答案。对于多字节字符,它们不会。
答案 1 :(得分:1)
我无法验证此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.