Character to number
Contents
Introduction
Sometimes it's necessary to extract a number from inside a string. Since RPG is strongly typed, that requires a data type conversion of some kind. There are several general mechanisms commonly used for this.
- Fixed-format's MOVE operation code
- One of the C library's conversion functions like atof()
- An RPG BIF (if at a recent enough version of IBM i)
- An RPG procedure to extract the numeric value
C function
To use one of the C functions, write a prototype and call it. A typical use is
D CvtDec PR 8F ExtProc('atof') D * Options(*String) Value C Eval(h) MyDecField = CvtDec(MyCharField)
Note that floating point is by it's nature imprecise. atoi() is another possibility. Note that the format of the numeric value inside the string might preclude this from working out.
RPG built-in function
%dec
and %dech
can do type conversions if on a recent enough version of IBM i (V5R3+). Note that the format of the numeric value inside the string might preclude this from working out.
RPG procedure to extract a numeric value from a character
IBM's Barbara Morris (Toronto Labs) has kindly donated some code to the public domain that will extract a numeric value from a character string.
H NOMAIN * Copy prototype for procedure getNum D/COPY GETNUM_PR *------------------------------------------------------- * getNum - see GETNUM_PR for details *------------------------------------------------------- p getNum b export D getNum pi 30p 9 D string 100a const varying D decCommaParm 2a const options(*nopass) D curSymParm 1a const options(*nopass) * defaults for optional parameters D decComma s 2a inz('.,') D cursym s 1a inz(' ') D result s 30s 9 inz(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 decComma = decCommaParm C endif C if %parms > 2 C eval cursym = cursymParm C endif * call getNumAny to do the work C callp getNumAny (string C : %addr(result) C : %len(result) C : %decpos(result) C : decComma C : curSym) C return result p getNum e *------------------------------------------------------- * getNumAny *------------------------------------------------------- p getNumAny b export D getNumAny pi D string 100a const varying D result * const D digits 10i 0 const D decimals 10i 0 const 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 resChars s 30a based(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 signByte s 1a based(pSignByte) 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 > 4 C eval decPoint = %subst(decComma : 1 : 1) C eval comma = %subst(decComma : 2 :1) C endif C if %parms > 5 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 * make sure that there is no overflow C if %len(decPart) > decimals C or %len(decPart) + %len(intPart) > digits * Force an overflow exception C z-add *hival overflowSrc 5 0 C z-add 0 overflowTgt 4 0 C eval overflowTgt = overflowSrc C endif * initialize the result to all zeros C eval %subst(resChars : 1 : digits) = *zeros * copy the digit strings into the correct positions in the * zoned variable, using the character overlay C eval decStart = digits - decimals + 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, make the result negative C if sign = '-' C eval pSignByte = %addr(resChars) + digits - 1 * Change the sign zone from x'f' to x'd' (b'1111' to b'1101') * using a mask of x'2' (b'0010') C bitoff X'20' signByte C endif p getNumAny e ----------------------------------------------------------- * Prototype file D getNum pr 30p 9 D string 100a const varying D decComma 2a const options(*nopass) D currency 1a const options(*nopass) D getNumAny pr D string 100a const varying D result * const D digits 10i 0 const D decimals 10i 0 const D decComma 2a const options(*nopass) D currency 1a const options(*nopass) *--------------------------------------------------------- * 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
External links
Categories
This article is a stub. You can help by editing it.