Cobol - 如何确定 PIC N 字段中内容的长度和位置?

Cobol - How do I determine the length and position of the content in a PIC N field?

我发现我倾向于以太大的块来解决问题,所以这是我的 尝试从更小、更具体的东西开始。

我专门处理 PIC N 字段,这些字段是国家字段。我需要为我正在处理的程序确定该字段中内容的长度和位置。

我说的具体字段定义如下:

05 Bank-CODE PIC N(10).

可以有前导空格,也可以有尾随空格。在某些时候,我也需要针对嵌入式空间对其进行测试。

基本上,目标是能够在没有空格的情况下处理该字段的内容。

现在,我知道如何确定字段本身的长度了: 05 BANK-CODE PIC N(10). 05 BK-LENGTH PIC S9(04) COMP. MOVE LENGTH OF BANK-CODE TO BK-LENGTH COMPUTE BK-LENGTH = FUNCTION LENGTH (BANK-CODE)

就是不知道BANK-CODE中内容的长度和位置怎么确定。

您正在寻找的是 "trim",或者允许您从字段中 trim 前导和尾随空格的信息。

COBOL 没有。除非,如前所述,您使用的是像 GnuCOBOL 这样的编译器。但我猜你正在使用 IBM 的企业 COBOL。如果是,名称和特定版本将显示在编译器输出列表的每一页的顶部。

不能因为 COBOL 没有 trim 而阻止您。这只是意味着您需要代码。

这里有一些来自 "out there"([=97= 的搜索引擎],link 很长,很长的故事)并找到关于 编码技巧的部分来自客户情况

MOVE ' This is string 1 ' TO TEXT1
COMPUTE POS1 POS2 = 0
INSPECT TEXT1
   TALLYING POS1
   FOR LEADING SPACES
INSPECT FUNCTION REVERSE(TEXT1)
   TALLYING POS2
   FOR LEADING SPACES
MOVE TEXT1(POS1:LENGTH OF TEXT1 - POS2 - POS1)
 TO TEXT2

MOVE ' This is string 1 ' TO TEXT1
PERFORM VARYING POS1 FROM 1 BY 1
  UNTIL TEXT1(POS1:1) NOT = SPACE
END-PERFORM
PERFORM VARYING POS2 FROM LENGTH OF TEXT1
   BY -1 UNTIL TEXT1(POS2:1) NOT = SPACE
END-PERFORM
COMPUTE LEN = POS2 - POS1 + 1
MOVE TEXT1(POS1 : LEN) TO TEXT2 (1 : LEN)

你会在文档中看到,正如你被告知的那样,FUNCTION REVERSE 有一些性能影响(第一段代码比第二段慢 31%),但要小心避免它.如果速度较慢 运行,则更容易编码和理解。如果您的子程序将被大量使用,那么考虑性能是值得的。

代码由 IBM 的 Tom Ross 提供。

Tom 的代码使用 "reference modification"。这是一种可以在编译时(如果开始位置和长度已知)或在 运行 时即时定义字段的子字段的方式,如果开始位置和长度是可变的。引用修改是一种非常快速的数据访问方式。这也是一种非常懒惰和草率的访问数据的方式,混淆了代码(可能会有一些意见在那里显示,其他人可能不会持有这种意见)。

下一段代码使用的不是引用修改:

       01  the-text                        PIC X(30).
       01  FILLER 
           REDEFINES the-text.
           05  FILLER 
               OCCURS 30 TIMES.
               10  the-byte-of-text        PIC X.

然后可以通过下标引用文本字节,而不是引用组项(文本)。

对于引用修改和下标,POS1 的定义可能相同。或者可以。我会选择 PIC 99 BINARY(BINARY/COMP/COMP-4 在 Enterprise COBOL 中是相同的)但你的同事可能会坚持使用 PIC S9(4) COMP(旧习惯难改)。

现在,如果您想要更快:

       PERFORM 
         VARYING                    POS1 
           FROM                     1 
           BY                       1 
         UNTIL                      ( NOT TEXT1-BYTE-IS-SPACE 
                                       ( POS1 ) )
       END-PERFORM 
       MOVE TEXT1 ( POS1 : )        TO TEXT2 

Tom 的代码中实际上缺少一块,TEXT2 的初始化。

此代码(我的)通过在引用修改中不使用 "length" 来处理这个问题。为什么不? COBOL 字段是固定长度的(可变长度字段除外),因此您不能 "get rid of" 尾随空格。对于那个例子,那么,不要费心去寻找尾随空格,并使用最后的 MOVE 来确保 TEXT2 中没有遗留任何数据(在 Tom 的例子中会有)。

请注意,我使用了 REDEFINES 和数据名称作为下标 (POS1) 和 88 级条件名称。除了速度更快,您还可以使代码更清晰。在一定限度内,可以同时进行。

对于您的任务,您确实想知道尾随空格的长度:

示例的一个问题是它们通常不完整,例如缺少初始化。另一件不完整的事情是所有代码都假定至少存在一个非空白(因为文字被用作源)。这通常是不现实的,而且在您的情况下绝对没有用。

人们通常会通过在 PERFORM 的终止条件中包含 "make sure I haven't run off the end" 来处理更一般的情况。但是多条件比较难理解,运行比较慢。

       IF field-in-use-is-blank
           PERFORM                  no-field-to-deal-with
       ELSE
           PERFORM                  field-to-deal-with
       END-IF

所以马上做两个不同的案例。在 field-to-deal-with 中,您可以知道至少有一个非空白字符。在无字段处理中,您知道整个字段都是空白的。

field-in-use-is-blank 是您字段上的 88 级条件名称。

   01  your-field                          PIC X(40).
       88  field-in-use-is-blank           VALUE SPACE.

请注意,我使用的名称仅用于说明。我总是为您的实际目的建议有意义的名称。

       PERFORM 
         VARYING                    POS2 
           FROM                     LENGTH OF TEXT1 
           BY -1 
         UNTIL                      ( TEXT1-SPACE-CHECK 
                                       ( POS2 )
                                     NOT EQUAL TO SPACE )
       END-PERFORM 
       COMPUTE LEN                  = ( POS2 
                                      - POS1 ) 
                                      + 1

从字段的末尾向后退,您不能使用 88 级。

现在你有 LEN。我会为所有东西使用不同的名字,但那就是我。

以下是相关的数据定义:

   01  FILLER REDEFINES TEXT1. 
       05  FILLER OCCURS 50 TIMES. 
           10  TEXT1-SPACE-CHECK           PIC X. 
               88  TEXT1-BYTE-IS-SPACE     VALUE SPACE.

   01  LEN                          COMP   PIC S9(4).
   01  POS1                         COMP   PIC S9(4).
   01  POS2                         COMP   PIC S9(4).

TEXT1 只是一个 50 字节的 PIC X 字段。给鸡蛋去皮的方法有很多种。上面的代码显示了 POS1 如何用于引用修改以及下标。 LEN、POS1 和 POS2 的大小和类型是最好的猜测。它们都可以是二进制的(让我现代一点,因为它只是一个打字的东西......)PIC 99。在某些情况下,该定义比原始定义更有效,否则相同。不要指望让你的任何前辈相信这一点。

COBOL 主要是 "team" 的东西。按照他们在您网站上完成的方式做事。如果本地 "standards" 很差或已过时,您可以随时尝试更改它们,但按照其他人的编码方式(技术)进行编码意味着更容易团队理解。显然使用有意义的名字本身就是一种好处,与技术无关。

以上是 PIC X(或 PIC A,但您不太可能看到这些)字段。 PIC N 有什么不同?只是 FUNCTION LENGTH 而不是 LENGTH OF.

但是,PIC N 存在潜在的性能问题。在后台,如有必要,编译器会将国家/地区转换为字母数字,然后再转换回来。为了性能,并且只有数字和普通的拉丁字母表,我只会在最后一刻将所有内容转换为 PIC N。这可能只是一个简单的 MOVE,编译器会为您生成代码。

忘记补充一点,您已经看到 link 到 "trimmer":https://codereview.stackexchange.com/q/69220/21548