You can simplify your code with the set of string-related BIFs presented in this TechTip. Master them and you'll be the one pulling the strings of your code and not the other way around.
Working with strings in RPG can be a real pain: all of those MOVE and CAT op codes and work variables with different lengths just to "stitch" the appropriate string together!
Don't take this the wrong way, but using MOVE and CAT to handle strings is so System/36! Over the years, IBM introduced several time-saving BIFs to handle almost every situation when it comes to string operations. In the previous TechTip, I introduced %CHAR and you probably already know %TRIM, but there's still a lot more to discover.
"Old" vs. "New" Ways
The code below depicts the old, "traditional" and the new, "BIF-esque" ways of performing a few string operations. Both scenarios perform the same task: splitting a string in two, adding some text in the middle, and stitching them back together. Let's start with the "traditional" approach:
D base_str S 100A INZ('THIS IS A TEST, 1, 2, 3')
D result S 100A INZ(*BLANKS)
D temp_str1 S 15A INZ(*BLANKS)
D temp_str2 S 84A INZ(*BLANKS)
D temp_str3 S 19A INZ(*BLANKS)
C MOVEL base_str temp_str1
* "temp_str1" is now 'THIS IS A TEST,'
C MOVE base_str temp_str2
* "temp_str2" is now '1, 2, 3'
* plus a lot of trailing blanks that I'm omitting
C temp_str1 CAT ' 0,' temp_str3
* "temp_str3" is now 'THIS IS A TEST, 0,'
C temp_str3 CAT temp_str2 result
* "result" is now 'THIS IS A TEST, 0, 1, 2, 3'
* plus a lot of trailing blanks that I'm omitting
Now for the new, "BIF-esque" approach:
D base_str S 100A INZ('THIS IS A TEST, 1, 2, 3')
D result S 100A INZ(*BLANKS)
D temp_str1 S 15A INZ(*BLANKS)
D temp_str2 S 84A INZ(*BLANKS)
D temp_str3 S 19A INZ(*BLANKS)
C EVAL temp_str1 = %SUBST(base_str : 1 : 15)
* "temp_str1" is now 'THIS IS A TEST,'
C EVAL temp_str2 = %TRIM(%SUBST(base_str : 16))
* "temp_str2" is now '1, 2, 3'
* without the %TRIM, it would be ' 1, 2, 3'
C EVAL temp_str3 = temp_str1 + ' 0, '
* "temp_str3" is now 'THIS IS A TEST, 0, '
C EVAL result = temp_str3 + temp_str2
* "result" is now 'THIS IS A TEST, 0, 1, 2, 3'
However, thanks to the EVAL op code and the BIFs, this could be much shorter.
In fact, it can be written in only one statement:
(…)
C EVAL result = %SUBST(base_str : 1 : 15)
C + ' 0, '
C + %TRIM(%SUBST(base_str :
16))
This is an "over the top" example, but surely you see the difference in readability and maintainability between the two scenarios: while the variable sizes are critical to the success of the MOVE and MOVEL operations, in the "BIF-esque" approach they are irrelevant, as long as they're big enough to hold the substrings they need to hold. Even if you're familiar with the BIFs used here, keep reading. You might find something that you didn't know about these BIFs.
Out with the Old, in with the New
Let's begin with %SUBST. This BIF is similar to the SUBST op code (which I could have used in the "traditional" approach instead of the MOVE op code, but chose not to), with the same three parameters: base string, start position, and length to extract. Actually, the SUBST op code has a fourth parameter (the target string), which doesn't exist in its BIF counterpart due to its function nature. Anyway, if the third parameter is not specified, the length is the length of the string parameter less the start value plus one. In other words, the start position and everything to its right will be extracted, as you can see from the temp_str2 assignment in the code above. If you're still a bit confused, here are a few simple examples to make things clearer:
- The value of %SUBST('Hello World' : 7) is 'World'
- The value of %SUBST('Hello World' : 5+2 : 10-7) is 'Wor'
- The value of % SUBST('abcd' + 'efgh' : 4 : 3) is 'def'
The first example, which omits the length parameter, returns everything to the right of position 7, including that character (see temp_str2's assignment above); the second one uses all three parameters and also illustrates the use of arithmetic operations in the start position and length parameters; you'll see how useful this can be later (see temp_str1's assignment above); finally, the third example shows a concatenation operation in the base string parameter; even though this might not be very common, its purpose here is to remind you that the CAT op code can be replaced by the '+' operator and used to simplify string concatenation (see temp_str3's and result's assignment above).
Do You %TRIM?
If you already knew %SUBST, it's possible that you also know %TRIM and its siblings, %TRIMR and %TRIML. What you might not know is that you can also use %TRIM to…well, trim characters other than the blank space. To do that, you just need to specify the characters to trim in the BIF's second (and optional) parameter:
D edited S 20A INZ('£******1.23*** ')
D trimmed S 20A Varying
C EVAL trimmed = %TRIM(edited : '$£*')
* Trims '£' and '*' from the edited numeric value
* "trimmed" is now '1.23***
'
However, note that blanks will not be trimmed, since a blank is not specified in the 'characters to trim' parameter. To do that, you need to add a blank space to the second parameter of the BIF, like so:
D edited S 20A INZ('£******1.23*** ')
D trimmed S 20A Varying
C EVAL trimmed = %TRIM(edited : '$£* ')
* Trims '£', '*' and ' ' from the edited numeric value
* "trimmed" is now '1.23'
It's possible to do the same with the aforementioned %TRIML (Trim leading characters) and %TRIMR (Trim trailing characters), but it will
only affect the characters to the left and right of the edited number from the example above, like this:
D edited S 20A INZ('£******1.23*** ')
D Ltrimmed S 20A Varying
D Rtrimmed S 20A Varying
C EVAL Ltrimmed = %TRIML(edited : '$£* ')
* "Ltrimmed" is now '1.23*** '
C EVAL Rtrimmed = %TRIMR(edited : '$£* ')
* "Rtrimmed" is now
'£******1.23'
By using BIFs as parameters to other BIFs, it gets easy to shorten the number of lines of code, but don't get carried away! It's crucial that you keep a sane balance between number of lines and readability.
Finally, you could argue that there are ways to determine the exact position of a substring within a string; finding the 'TEST, ' substring in the example above can be performed with the SCAN op code. That's correct, and it will be discussed in the next TechTip. Meanwhile, comment away in the Comments section below!
LATEST COMMENTS
MC Press Online