I have received an email asking me the following question:
How can I validate numbers in RPGLE /free without using testn?
I have spent a considerable amount of time dealing with data from Microsoft Excel spreadsheets that has been uploaded to the IBM i (AS400). It is easy to use the TESTN operation code to test ideally formatted "00123456", but what about "123456 " or "1,234.56 "?
In this post I am going to use five fields that you could encounter trying when converting an alphanumeric to a numeric field:
01 D A0 S 8 inz 02 D A1 S 8 inz('00001234') 03 D A2 S 8 inz('1234') 04 D A3 S 8 inz('1234.56') 05 D A4 S 8 inz('1,234.56')
The TESTN operation code offers three indicators to report back to us the results of the test:
- First indicator position (71-72) - The field contains numeric characters. In the example below indicator 01 is used.
- Second indicator postion (73-74) - The field contains at least one leading blank, for example " 1234".
- Third indicator position (75-76) - The field is blank. In the example below indicator 02 is used.
C testn A0 01 02 C testn A1 01 02 C testn A2 01 02 C testn A3 01 02 C testn A4 01 02
So what happens when the TESTN is used to test our fields?
- A0 - indicator 02 is on as the field is blank.
- A1 - indicator 01 is on as the field only contains numeric characters.
- A2 and A3 - no indicator is on as the blanks at the end of the fields fail the TESTN test.
- A4 - no indicator is on as it contains an invalid character, the comma (,).
I have seen people use the Check Characters BIF, %CHECK, to test the characters in the field, although I wonder why they do.
/free 01 i = %check('0123456789.':A0) ; 02 i = %check('0123456789.':A1) ; 03 i = %check('0123456789.':A2) ; 04 i = %check('0123456789.':A3) ; 05 i = %check('0123456789.':A4) ;
The field i contains the first character not in the values listed.
- A0 - i = 1 as blank is not in the allowed list of characters.
- A1 - i = 0 success! The field only contains numeric characters.
- A2 - i = 5 as the fifth character in the field is blank.
- A3 - i = 8 as the eighth character in the field is blank.
- A4 - i = 2 as the second character is a comma (,).
I would use the Convert to Decimal BIF, %DEC, within a MONITOR group. For more information about the MONITOR group read the post MONITOR for errors in RPG. I am not going to repeat the code below five times, I am just going to show one of the conversions as they would all be indentical.
/free 01 monitor ; 02 N = %dec(Ax:8:2) ; 03 on-error ; 04 dsply Ax ; 05 endmon ;
On line 2 I am converting the alphanumeric field to a numeric field of 8,2. If this conversion produces an error I am displaying, line 4, the value of the alphanumeric field. I would never do that in a production program, I would have some error handing in place. But as this is a test program I am using the DSPLY operation code to show me the error.
- A0 - error as blanks cannot be converted to a number.
- A1, A2, A3 - success!
- A4 - error as the comma cannot be converted.
To cope with the problems caused by A0 and A4 I change the code to this:
/free 01 if (Ax = ' ') ; 02 N = 0 ; 03 else ; 04 Ax = %xlate(',':' ':Ax) ; 05 monitor ; 06 N = %dec(Ax:8:2) ; 07 on-error ; 08 dsply Ax ; 09 endmon ; 10 endif ;
Line 1 tests if the alphanumeric field is blank, A0. If it is then zero is move to N.
Line 4 uses the Translate BIF, %XLATE, to translate the comma to a blank, if one is present. A4 is translated from "1,234.56" to "1 234.56", and then converted to a number on line 6.
The statement above may look more complicated than the old TESTN, but as you can see that it is a better way to validate and convert an alphanumeric representation of a number to a numeric field.
You can learn more about these from IBM's website:
This article was written for IBM i 7.1, and it should work with earlier releases too.