【问题标题】:Versatile string manipulation procedure in RPGRPG中的多功能字符串操作程序
【发布时间】:2013-03-06 16:57:49
【问题描述】:

RPG 中的另一件事我永远不知道如何做正确:编写字符串操作函数/过程。

由于 RPG 中的大多数时间字符串具有固定长度(至少对于我们的程序而言),而且也许更重要的是它们总是具有有限长度,所以当我想编写一个通用程序时,我总是有点迷茫字符串操作。

如何编写一个处理任意长度字符串的过程?有问题吗,如果我这样做功能风格(如text = manip_str(text);)?如果我直接操纵参数(如manip_str(text);),它是否适用于不同的长度?

我将发布我自己的尝试作为答案,但其中存在一些我不确定的问题。你是怎么做的,我敢肯定 很多 曾经或一千次做过类似的任务。欢迎使用不同的方法,最好是提及这些方法的问题。

在你问之前:我对 (EBCDIC) 字节字符串和 (UTF-16) unicode 字符串有这个问题。但我可以接受两次手术,每次一次。

【问题讨论】:

  • 我们称它们为定长字符串。即使是可变长度的字符串也有一个有限的限制。如果您发现一个实际上具有无限存储的系统,请告诉我。 ;-)
  • @WarrenT 当然,计算机中的一切都是有限的。但在 RPG 中,我必须决定声明:该字符串不会超过 x 个字符。在其他语言(高,如 python 或低如 c)中,我只使用我的变量,而不关心它是 2 个字符还是 1000000(或尽可能多的内存)。对我来说,这是一个区别。也许你也可以在 RPG 中使用指针,但它们在 C 或 C++ 中并不自然。

标签: string function procedure rpgle rpg


【解决方案1】:

RPG 中的大多数字符变量确实是固定长度的。其中表示有限长度。定义为 50a 的字符总是包含正好 50 个字符。评估 myChar = 'A';将导致 myChar 包含 50 个字符:字母 A 后跟 49 个空格。这很无聊,但很重要。

第二个无聊但重要的一点是要了解调用者分配内存,而不是被调用者。如果调用者声明 myChar 50a 而被调用者声明 myParm 65535a,则调用者只初始化了 50 个字节的存储空间。如果被调用者尝试使用 myParm 超过第 50 个字节,则它正在使用条件未知的存储。正如他们所说,可能会出现不可预知的结果。

这是您关于处理字符变量的子过程的背景问​​题,该字符变量的大小事先不为子过程所知。处理这个问题的经典方法是不仅传递字符变量,而且传递它的长度。 eval myProcedure(myChar: %len(myChar));这有点难看,它迫使每个调用者计算 myChar 的长度。如果子过程可以询问传入的参数以找到调用者如何定义它,那肯定会很好。

IBM 通过他们称为操作描述符的东西提供了这样的工具。使用操作描述符,调用者将有关字符参数的元数据传递给被调用者。一个通过CEEDOD API 检索它。有一个使用 CEEDOD here 的例子。

基本上,子过程需要声明它需要操作描述符:

 dddeCheck         pr              n   opdesc
 d test                          20a   const options(*varsize)

然后调用者对子过程进行正常的调用:

if ddeCheck(mtel) = *on;               // 10 bytes
...
endif;
if ddeCheck(mdate: *on) = *on;         // 6 bytes
...
endif;

请注意,调用者将不同大小的固定长度变量传递给子过程。

子过程需要使用CEEDOD来查询传入参数的长度:

     dddeCheck         pi              n   opdesc
     d test                          20a   const options(*varsize)
...
     dCEEDOD           pr
     d parmNum                       10i 0 const
     d descType                      10i 0
     d dataType                      10i 0
     d descInfo1                     10i 0
     d descInfo2                     10i 0
     d parmLen                       10i 0
     d ec                            12a   options(*omit)

     d parmNum         s             10i 0
     d descType        s             10i 0
     d dataType        s             10i 0
     d descInfo1       s             10i 0
     d descInfo2       s             10i 0
     d parmLen         s             10i 0
     d ec              s             12a
...
       CEEDOD (1: descType: dataType: descinfo1: descinfo2: parmlen: *omit);

此时,parmlen 包含调用者定义的传入变量的长度。现在由我们来处理这些信息。如果我们正在逐个字符处理,我们需要做这样的事情:

for i = 1 to parmLen;
  char_test = %subst(test: i: 1);
  ...
endfor;

如果我们作为单个字符串处理,我们需要做这样的事情:

returnVar = %xlate(str_lc_letters_c: str_uc_letters_c: %subst(s: 1: parmLen));

重要的是永远不要引用输入参数,除非该引用以某种方式受到调用者定义的实际可变长度的限制。这些预防措施仅对固定长度变量是必需的。编译器已经知道变长字符变量的长度。

关于编译器通过 CONST 将 myFixed 映射到 myVarying 的方式,了解它是如何工作的。编译器会将 myFixed 中的所有字节复制到 MyVarying 中——所有这些字节。如果 myFixed 为 10a,则 myVarying 将变为 10 个字节长。如果 myFixed 为 50a,myVarying 将变为 50 字节长。始终包含尾随空格,因为它们是每个固定长度字符变量的一部分。这些空格对于翻译过程(忽略空格的过程)并不重要,但它们对于将字符串居中的过程可能很重要。在这种情况下,您需要使用操作描述符或执行类似 upperVary = str_us(%trimr(myFixed));

的操作

【讨论】:

  • 感谢您将我指向CEEDOD,我们将来会将其用于我们的服务计划。并解释背景,太棒了!但是,仍然不满足于从过程中返回字符串。我想我们会改为操作参数,我知道会发生什么。
  • 我错过了......也许你可以问一个关于在 RPG 中返回角色值的新问题......有一个具体的例子来说明困扰你的事情吗?
【解决方案2】:

我发现在 RPG 中最灵活的字符串传递方式适用于 64k-varlength 字符串并使用 *varsize 传递(它实际上应该只发送传递的字符串中的字节数,因此 64k 不应该是问题——我想我发现了 Scott Klement 建议的某个地方)。在这里,我将如何使用它编写一个仅 A-Z 的大写函数(因为它是一个最基本的示例):

 * typedefs:
Dstr_string_t     S          65535A   VARYING TEMPLATE

 * constants:
Dstr_uc_letters_c C                   'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
Dstr_lc_letters_c C                   'abcdefghijklmnopqrstuvwxyz'

 * prototype:
Dstr_uc           PR                  like(str_string_t)       
D s                                   like(str_string_t)       
D                                       options(*varsize) const

 * implementation:
Pstr_uc           B                   export                   
D                 PI                  like(str_string_t)       
D s                                   like(str_string_t)       
D                                       options(*varsize) const
 /free                                                         
  return %xlate(str_lc_letters_c:str_uc_letters_c:s);          
 /end-free                                                     
Pstr_uc           E 

现在有很多事情让我担心:

  • 我传递给它的固定长度字符串会不会有一些问题?
  • 这种“只传递所需的字节数”是否也适用于返回值?每次我想大写 3 个字符字符串时,我都不想保留和传递数千个字节。
  • 它只能灵活到 64k 字节。但我认为这在理论上更多是我们的程序存在的问题——至少目前是这样......

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多