我正在寻找一种方法来计算字符串在不使用SQL的情况下出现的次数。
我对RPGLE比较陌生,我创建了一个测试程序,它以字符格式接受用户输入,进行验证,并将成功的数据转换为数字。其中一个输入可以是正整数或负整数。在进行验证时,我测试' - '处于第一个位置并使用%CHECK确保输入为0-9或' - '。 (例如'-10'传球,'1-0'失败)
但是,如果输入多次出现' - '符号,例如'-1-1-1-1',则当程序尝试转换为数字时,它会通过验证并崩溃。
我知道我可以在我的DDS中使用编辑代码来让系统处理这个,但我正在尝试学习不同的方法来让我的程序控制验证。在我的研究中,我发现TestN和Module / Convert /%Error是可以用来确保输出是数字的方法,但我不能测试这个特定的实例,所以我可以提供有意义的反馈。
有没有办法计算' - '的出现次数,所以我可以测试一下?
由于我的意图似乎有些混乱,我将再添一个例子。如果我想知道'HELLO'这个词中出现多少次字母“L”,那么最好的方法是什么。
答案 0 :(得分:2)
根据评论和编辑,让我们忽略任何特定的用例,并且真的只回答"如何使用没有嵌入式SQL的RPG计算字符串中特定字符的出现次数?"
发表评论
我只是好奇他们是否与BIF类似,比使用SCAN更容易返回结果
答案是:目前还没有任何BIF可以直接给你结果。也就是说,没有像
那样的东西occurrences = %COUNT(needle:haystack);
如果您使用的是7.1或更高版本,最优雅的方式可能是使用%SCANRPL
,这类似于SQL REPLACE
。假设needle
是单个字符而haystack
是变长字符串,则类似
occurrences = %LEN(haystack) - %LEN(%SCANRPL(needle:'':haystack));
也就是说,如果删除所有出现的haystack
,请查看needle
缩短了多少。 (通过将此结果除以needle
的长度,您可以将此概括为长于一个字符的针。)
如果您使用的是早期版本,那么您的决定可能在您已完成的%SCAN
重复之间,或逐个字符循环haystack
之间。前者可能效率更高,特别是如果针密度"非常低,但后者更容易编码,更容易阅读和维护。
我现在要注意的是"没有SQL"约束是一种非常人为的约束,就像你在学校作业中遇到的一样。在现实世界的系统中,您不太可能访问RPG但不能访问RPG-with-embedded-SQL,因此如果有一个优雅,可读的SQL解决方案,那么为了实际使用,那里没有理由把它排除在外。
答案 1 :(得分:1)
%scan()bif接受3参数 - 起始位置。因此,您可以从最后一次点击的位置开始进行多次扫描。
但是,我并不喜欢这种手动验证。从性能的角度来看,假设大多数数据都是好的,那么您就会浪费周期。更重要的是,您已经制定的测试,要求' - '处于第一位意味着' -10'会失败;
如果需要,我更喜欢简单地执行catch异常转换。
monitor;
myValue = %dec(myString);
on-error;
// let the user know
endmon;
最后,TESTN
已过时,应予以避免。它可能无论如何都不会以你想要的方式工作。例如(IIRC),' 5A' 传递 TESTN测试。
RPG手册本身就是关于TESTN的说法:
自由格式语法 - (不允许 - 而不是在使用它之前测试变量,在MONITOR组中编码变量的使用并使用ON-ERROR处理任何错误。请参阅错误处理操作。 )
答案 2 :(得分:1)
RPG是强类型语言,因此一般来说,如果需要数字,请使用数字字段。不要使用字符字段,然后测试并转换为数字。显示文件(使用DDS)旨在轻松完成此任务(要求用户输入数字)。
那就是说,有时候你无法控制这种输入。您可能正在处理EDI交易或其他文件传输,而另一方将文本放入字段中,并由您来提取数字部分。对于这样的情况,您会收到类似于' - $ 45,907.12'你需要做的不仅仅是计算减号的数量。
IBM的Barbara Morris有posted the following code,这是从字符字段中提取数值的一个例子。它理解减号,小数分隔符,小数点和货币符号。
< ----- * / COPY文件的原型从这里开始----->
*---------------------------------------------------------
* getNum - procedure to read a number from a string
* and return a 30p 9 value
* Parameters:
* I: string - character value of number
* I:(opt) decComma - decimal point and digit separator
* I:(opt) currency - currency symbol for monetary amounts
* Returns: packed(30,9)
*
* Parameter details:
* string: the string may have
* - blanks anywhere
* - sign anywhere
* accepted signs are: + - cr CR ()
* (see examples below)
* - digit separators anywhere
* - currency symbol anywhere
* decComma: if not passed, this defaults to
* decimal point = '.'
* digit separator = ','
* currency: if not passed, defaults to ' '
*
* Examples of input and output (x means parm not passed):
*
* string | dec | sep | cursym | result
* ---------------+-----+-----+--------+------------
* 123 | x | x | x | 123
* +123 | x | x | x | 123
* 123+ | x | x | x | 123
* -123 | x | x | x | -123
* 123- | x | x | x | -123
* (123) | x | x | x | -123
* 12,3 | , | . | x | 12.3
* 12.3 | x | x | x | 12.3
* 1,234,567.3 | x | x | x | 1234567.3
* $1,234,567.3 | . | , | $ | 1234567.3
* $1.234.567,3 | , | . | $ | 1234567.3
* 123.45CR | x | x | x | -123.45
*
* Author: Barbara Morris, IBM Toronto Lab
* Date: March, 2000
*---------------------------------------------------------
D getNum pr 30p 9
D string 100a const varying
D decComma 2a const options(*nopass)
D currency 1a const options(*nopass)
< ----- * / COPY文件的原型在这里结束----->
< ----- *测试程序从这里开始----->
* Copy prototype for procedure getNum
D/COPY GETNUM_P
D res s like(getNum)
D msg s 52a
C *entry plist
C parm p 32
C parm dc 2
C parm c 1
C select
C when %parms = 1
C eval res = getNum(p)
C when %parms = 2
C eval res = getNum(p : dc)
C when %parms = 3
C eval res = getNum(p : dc : c)
C endsl
C eval msg = '<' + %char(res) + '>'
C msg dsply
C return
&lt; ----- *测试程序在这里结束-----&gt;
&lt; ----- *模块GETNUM从这里开始-----&gt;
H NOMAIN
* Copy prototype for procedure getNum
D/COPY GETNUM_P
p getNum b
D getNum pi 30p 9
D string 100a const varying
D decComma 2a const options(*nopass)
D currency 1a const options(*nopass)
* defaults for optional parameters
D decPoint s 1a inz('.')
D comma s 1a inz(',')
D cursym s 1a inz(' ')
* structure for building result
D ds
D result 30s 9 inz(0)
D resChars 30a overlay(result)
* variables for gathering digit information
* pNumPart points to the area currently being gathered
* (the integer part or the decimal part)
D pNumPart s *
D numPart s 30a varying based(pNumPart)
D intPart s 30a varying inz('')
D decPart s 30a varying inz('')
* other variables
D intStart s 10i 0
D decStart s 10i 0
D sign s 1a inz('+')
D i s 10i 0
D len s 10i 0
D c s 1a
* override defaults if optional parameters were passed
C if %parms > 1
C eval decPoint = %subst(decComma : 1 : 1)
C eval comma = %subst(decComma : 2 :1)
C endif
C if %parms > 2
C eval cursym = currency
C endif
* initialization
C eval len = %len(string)
* begin reading the integer part
C eval pNumPart = %addr(intPart)
* loop through characters
C do len i
C eval c = %subst(string : i : 1)
C select
* ignore blanks, digit separator, currency symbol
C when c = comma or c = *blank or c = cursym
C iter
* decimal point: switch to reading the decimal part
C when c = decPoint
C eval pNumPart = %addr(decPart)
C iter
* sign: remember the most recent sign
C when c = '+' or c = '-'
C eval sign = c
C iter
* more signs: cr, CR, () are all negative signs
C when c = 'C' or c = 'R' or
C c = 'c' or c = 'r' or
C c = '(' or c = ')'
C eval sign = '-'
C iter
* a digit: add it to the current build area
C other
C eval numPart = numPart + c
C endsl
C enddo
* copy the digit strings into the correct positions in the
* zoned variable, using the character overlay
C eval decStart = %len(result) - %decPos(result)
C + 1
C eval intStart = decStart - %len(intPart)
C eval %subst(resChars
C : intStart
C : %len(intPart))
C = intPart
C eval %subst(resChars
C : decStart
C : %len(decPart))
C = decPart
* if the sign is negative, return a negative value
C if sign = '-'
C return - result
* otherwise, return the positive value
C else
C return result
C endif
p e
&lt; ----- *模块GETNUM在这里结束-----&gt;
答案 3 :(得分:1)
SCAN操作代码(OpCode)[与%SCAN内置对比]具有几乎的能力,匹配要求以实现字符串中字符出现的计数;通过将一个数组指定为结果字段[或者,在MI的说法中,接收器;用于参考RPG参考和近等效MI指令的文档片段]。然而,第二步是必需的。
http://www.ibm.com/support/knowledgecenter/api/content/ssw_ibm_i_71/rzasd/sc092508999.htm#zzscan
SCAN(扫描字符串)
自由格式语法(不允许......
......
SCAN操作扫描字符串(基本字符串)...
...
http://www.ibm.com/support/knowledgecenter/ssw_ibm_i_71/rzatk/SCAN.htm
扫描(扫描)
以下代码源能够被编译为可调用绑定的RPGLE程序[至v5r1并且可能在之前的几个版本中];当被调用时,接受一个32字节的输入字符串[因此很容易通过命令行CALL CHARCOUNT PARM('字符串指定''i')/ *调用显示的结果:DSPLY 3 * /]和一个字节的字符值作为参数。第一个参数是计算指定为第二个参数的字符出现次数的字符串。输出是通过输入字符串的存储器的DSPLY操作码重写为编辑的数字出现次数。按原样提供,没有进一步的评论,除了说明%lookup依赖于对数组的顺序搜索:
H dftactgrp(*no) actgrp(*CALLER)
D CHARCOUNT PR ExtPgm('CHARCOUNT')
D inpstring 32A
D findchar 1A
D CHARCOUNT PI
D inpstring 32A
D findchar 1A
D clen C const(32)
D decary S 5S00 dim(clen)
D i S 2P00
c findchar scan inpstring decary
/free
// locate first zero-value array element
i = %lookup(0:decary) - 1 ;
inpstring = %editc(i:'3') ;
DSPLY inpstring ;
*INLR = *ON ;
/end-free