A Bevy of BIFs: %CHAR, %EDITC and %EDITW
April 15, 2009 Jon Paris
“I need to convert a numeric value into a character string. How do I . . . ?”
This type of question is often asked by RPGers in these days of comma separated value files, XML documents, and Web pages (HTML). Generating such files has become a common requirement in the lives of RPGers. If they aren’t yet commonplace in your corner of the world, then they soon will be; if that doesn’t happen soon, maybe you should be concerned about the future of your favorite platform in your organization!
So let’s start by taking a quick look at one of my favorite built-in functions: %Char. Originally introduced to handle conversion of date fields to a character form, %Char was quickly upgraded for use with numeric fields and expressions. But the way in which it operates often catches programmers by surprise. Why? Because %Char performs leading zero suppression on the input and then trims the resulting string to remove leading and trailing blanks. As a result, the length of the resulting string varies depending on the value in the field being converted. As we will see later, this is very different from %EDITC (and its companion %EDITW), which will always produce identical length output from a given input field definition and edit code combination–regardless of the actual content of the field.
As a result, when you run the code below, the first DSPLY message (A) will say “%Char value is (12.34)” and the second (B) “%Char value is (10012.34)”. When you are building text such as that used in the message here, this is a good thing. It saves you having to worry about stripping the blanks etc. It will even place a minus sign in front of negative numbers and, as you can see, will insert a decimal point when the expression contains decimal places. Very useful.
But what if you want to simply convert a numeric value to its character equivalent? For example, to replace an old-fashioned MOVE operation. If you try to use %Char for that purpose you will be disappointed for many reasons. For one you may find an unwanted decimal point inserted as in our examples, and for another, because you’ll either end up with trailing spaces in the output field (C) ” Result in char field is (12.34 )”, or worse still, truncation of the decimal places (D) ” Result in char field is (10012.3)” and that’s probably not what you expect, or indeed want.
Replacing the MOVE Operation
So how do you handle the requirement to replace a MOVE operation? The answer is %EditC. %EditC applies an edit code to a numeric field just as it would if you used that code on an O-spec or in a DDS definition. It then gives you back the edited character string for inclusion in whatever other text you want. So what’s the magic code that allows us to insert leading zeros and not have to worry about decimal place insertion etc? ‘X’ marks the spot! The X edit code will retain leading zeros, and will not insert a decimal point, comma, or anything else. The result is that our test program will output (E) “%EditC value is (0001234)” and (F) “%EditC value is (1001234)”. Note that the length of the display string is identical in each case and any negative values will be indicated by an alpha character in the right-most position of the field just as they would have been with a MOVE.
We won’t go into details of all of the edit code options available. As we noted earlier they are identical to those used on O-specs and in DDS, as are the edit words used by %EditW. Having said that, there is one difference between the way certain editing requirements are specified with %EditC relative to O-specs. If you require the resulting string to have leading zeros replaced by asterisks, then the keyword *ASTFILL should be specified as the third parameter to %EditC. Similarly, if you want a floating currency sign to be added to the field, you can specify *CURSYM for the default value, or enter a single character of your own choosing to have that act as the floating currency symbol.
As you can see, there’s a lot you can do with these BIFs – so if you have been using O-specs to format this kind of data, perhaps it is time to revise your coding techniques.
D testNum S 7p 2 inz(12.34) D testChar S 7a /Free (A) Dsply ('%Char value is (' + %Char(testNum) + ')'); testNum += 10000; (B) Dsply ('%Char value is (' + %Char(testNum) + ')'); testNum = 12.34; // Reset to original value // Attempt to use %Char() as equivalent to MOVE testChar = %Char(testNum); (C) Dsply ('Result in char field is (' + testChar + ')'); testNum += 10000; testChar = %Char(testNum); (D) Dsply ('Result in char field is (' + testChar + ')'); testNum = 12.34; // Reset to original value (E) Dsply ('%EditC value is (' + %EditC(testNum: 'X') + ')'); testNum += 10000; (F) Dsply ('%EditC value is (' + %EditC(testNum: 'X') + ')'); *InLR = *On;
Jon Paris is one of the world’s most knowledgeable experts on programming on the System i platform. Paris cut his teeth on the System/38 way back when, and in 1987 he joined IBM’s Toronto software lab to work on the COBOL compilers for the System/38 and System/36. He also worked on the creation of the COBOL/400 compilers for the original AS/400s back in 1988, and was one of the key developers behind RPG IV and the CODE/400 development tool. In 1998, he left IBM to start his own education and training firm, a job he does to this day with his wife, Susan Gantner–also an expert in System i programming. Paris and Gantner, along with Paul Tuohy and Skip Marchesani, are co-founders of System i Developer, which hosts the new RPG & DB2 Summitconference. Send your questions or comments for Jon to Ted Holt via the IT Jungle Contact page.