Extract Numbers from a String using RPGLE

Programming

Oct 12

RPG EXAMPLE to read NUMERIC from ALPHAMERIC

AKA: how to select only the number from an address in a field, or file data

A little while ago, I wanted to extract out the numerics from a string of data:

For example (a) if I feed in a phone number like “(540)-123 – 1234” but I just want to see 5401231234 or maybe (b) “111 High Street, 5th District, Charleston, SC 29466” then I want to get “111529466” returned.

Obviously there are several ways of doing this. But a few techniques sprang to mind so lets do some timings using common variable names. These code examples are using values of (a) = long varying variable with an Address in it and (b) variable defined as 15,0 containing returned numeric value. To do some timings on this, I read 10,000 address fields from a customer master file and fed this data into the following routines.

Assuming we have the long variable called longVariable with the address in it and we want to extract out numbers and return them in the value called RtnValue — lets look at some examples

This gave me a sensible execution time that i could do a rough timing with:

METHOD 1 – Read through the address string, position by position to find the numeric values:

RPG Code SnippetFor X = 1 to %len(longVariable);
  StringChar = %subst( longVariable : X : 1);
  If StringChar >= ‘0’ and StringChar <= ‘9’;
    Eval rtnValue = %Trim(rtnValue) + StringChar;
  Endif;
 EndFor;

10k results each saying “111529466” Correctly

Runtime – 2.15 seconds

METHOD 2 – Use %XLATE to remove all non-numerics then use %DEC to convert to numeric

stringClean = %xlate(rmvThis:Blanks:longVariable);
 If StringClean <> *blanks;
   rtnValue = %dec(stringClean:30:0);
 else;
   rtnValue = 0;
 endif;

10K results each saying “111529466” Correctly

Runtime – 2.09 seconds

NOTE: I have a slight hesitance here because of the question of receiving unknown HEX data in the input string. The XLATE doesnt know about it so it might miss it and fail to extract.

METHOD 3 – use the ‘C’ libary ATOF function to parse the string and return numerics

‘atof’ is a function in the C programming language that converts a string into a floating point numerical representation. atof stands for ASCII to float

rtnValue = %dech(atof(%trim(longVariable)):15:0);

10K results each saying “111” **ERROR** it seems that ATOF only returns the first number set if can find.

Runtime – 0.29

I could have written this into an array with a lookup but I know that would be a slower solution thant option (1). *IGNORED*

METHOD 4 – use SQL

Exec SQL Set :rtnValue = regexp_replace(trim(cast(:longVariable as varchar(29) ccsid 37)), '["[0-9]]', '', 1, 0, 'i');

10K results each saying “111529466” Correctly

Runtime – 2.95

*SLOWEST*

METHOD 5 – Use IBM i (MI) CVTEFN (Convert external form to numeric)

The IBM i Operating System (the new version of the old AS/400, iSeries) has something that is at a lower level than the C language, and that is the Machine Interface (MI). In effect, this is IBM i Assembly language. While I don’t want to get into the virtues of MI programming, I do advocate using a bit of MI now and then, especially today, since you can call an MI instruction directly from within RPG IV.

The MI instruction CVTEFN (Convert external form to numeric) allows you to convert from character to numeric. The resulting value can be virtually any numeric data type and length. The documentation on CVTEFN states the following:

“Scans a character source for a valid decimal number in display format, removes the display character, and places the result in receiver.”

The syntax diagram for CVTEFN is as follows:

void _CVTEFN (_SPCPTR receiver, _DPA_Template_T *rcvr_descr, _SPCPTRCN source, unsigned int *src_length, _SPCPTR mask);

I had high hope for this but it failed repeatedly. Then upon reading the IBM documentation it said “results could not be trusted”. *SIGH*

This option is ignored.

and thats about… I hope it helps somebody out?!

Follow

About the Author

IBM i Software Developer, Digital Dad, AS400 Anarchist, RPG Modernizer, Alpha Nerd and Passionate Eater of Cheese and Biscuits. Nick Litten Dot Com is a mixture of blog posts that can be sometimes serious, frequently playful and probably down-right pointless all in the space of a day. Enjoy your stay, feel free to comment and in the words of the most interesting man in the world: Stay thirsty my friend.