Most of us have used the SCAN opcode or its contemporary %SCAN built-in function to search a field for a specific piece of data. While %SCAN is a bit less powerful, it is now more often used than the SCAN opcode.
One tip I included in my recent book, RPG TNT: 101 Dynamic Tips 'n Techniques with RPG ("RPG TNT") shows you how to scan use %SCAN while ignoring upper/lowercase differences.
The inability to search while ignoring upper/lowercase letters is a serious shortcoming in %SCAN. Where the heck is %SCANI? But being a programmer, I realize this shortcoming can be overridden by simply nesting one expression inside another.
For example, building a simply translation table to convert the data to all upper or all lowercase letters can be accomplished with twonamed constants, as follows:
D UP C 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
D low C 'abcdefghijklmnopqrstuvwxyz'
Using these two named constants in conjunction with the XLATE opcode or %XLATE built-in function, we can simulate a %SCANI() (scan while ignoring case) built-in function, for example:
/free
if (%scan('pickles' : %xlate(up:low:myData)) > 0);
// Got it! :)
endif;
/end-free
In this example, the %XLATE built-in function converts the data in MYDATA to all lowercase letters. That lowercase value is then scanned by the %SCAN built-in function. Let's look at it a bit closer.
First, convert the data in MYDATA to all lowercase letters:
%xlate(up:low:myData)
This uses the UP and LOW named constants to create an ad hoc conversion table. The built-in function %XLATE searches through MYDATA and converts each uppercase character to the corresponding lowercase character. The actual data in MYDATA is not modified; instead, %XLATE creates an all uppercase copy of the contents of MYDATA.
The return value from the %XLATE function is passed to the %SCAN built-in function. It is that return value that is searched by %SCAN.
I conveniently specified the search pattern (the first parameter of %SCAN) in all lower case, so it doesn't need to be converted. If, however, a field with data entered by an end user or read from a database record were specified, I would also need to repeat the %XLATE function on it as well. For example:
%scan(%xlate(up:low:searchData):%xlate(up:low:myData));
In this situation, the results of these two %XLATE functions are used by the %SCAN function.
%SCAN returns the position of the search pattern within the data being searched, or zero if the scan finds nothing. By comparing the results of %SCAN to zero, we can determine if data is found, as follows:
if (%scan('pickles' : %xlate(up:low:myData)) > 0);
The results of %SCAN are compared to zero. If greater than zero, then %SCAN located the search pattern ('pickles' in this example) in the data being searched.
Simple techniques such as this one that use the power of built-in functions and nested expression can add new features to RPG much more easily than hand-coded routines that are often prone to errors.
What else can you think of that would be just a easy? Write to me here and I'll try to include it in a future issue.