Case Insensitive Scan for Using %SCAN

Article ID: 54824

Two Search Methods for RPG IV; The Easy and the Powerful

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.

ProVIP Sponsors

ProVIP Sponsors