Advanced Pattern Matching in RPG
January 12, 2005 Michael Sansoterra
The code for this article is available for download.
SQL has many great features, including the LIKE predicate. LIKE’s power is manifest in its ability to have multiple wild cards in a search pattern. Unfortunately, RPG’s closest analog to LIKE is the %SCAN built-in function, which is limited to searching a string for a single substring.
Even though %SCAN’s power is limited, a little extra code can be used to simulate LIKE. The code in program LikeR.RPGLE contains subprocedure Like. The parameters for the Like subprocedure are:
Like(search string:pattern[:wildcard])
An indicator variable is returned by Like to indicate whether the string contains the requested pattern. The wildcard parameter is optional; if unspecified, the percent sign (%) will be assumed.
For the purpose of illustrating the Like subprocedure’s power, program LikeR.RPGLE can be called from the command line with two or three arguments (search, pattern, and the optional wildcard). The Dsply opcode is used to indicate with a 1 or a 0 as to whether the pattern matched.
Samples
The trick to this type of pattern matching with %SCAN is to break the pattern into its components and search for each component sequentially.
Search String | Pattern | Wildcard | Match |
ABCDEFGHIJKLMNOPQRS | %G%Q%S% | % | Yes |
ABCDEFGHIJKLMNOPQRS | A%P | % | No |
The % is a test% | *is*test* | * | Yes |
RPG is a great language | is a great% | % | No |
A1064 | A1064 | % | Yes |
For comparative purposes, here are a few code examples of how Like compares to %Scan:
Example 1
Search='The quick brown fox'; // Search for pattern assuming the default wildcard (%) If Like(Search:'%quick%fox%'); Dsply 'LIKE %quick%fox%' '' *InLR; EndIf; // // Here is the equivalent use of the scan op-code // If %Scan('quick':Search)>*Zero And %Scan('fox':Search)>%Scan('quick':Search); Dsply '%SCAN %quick%fox%' '' *InLR; EndIf;
Example 2
Search='The quick brown fox'; // Test if pattern begins with "The" and ends with "fox" If Like(Search:'The%fox'); Dsply 'LIKE The%fox' '' *InLR; EndIf; // The equivalent RPG code is // (actually "bullet proof" code would be much longer because // it would test acceptable string lengths, start pos, etc.) If %Subst(Search:1:3)='The' And %Subst(Search:%Len(Search)-2:3)='fox'; Dsply 'SCAN The%fox' '' *InLR; EndIf;
As you can see, the Like subprocedure provides shorter code and offers more flexibility.
Here are a few additional notes on the LIKE subprocedure:
- It does not recognize single character substitution (the underscore _ character).
- The pattern matching is case-sensitive.
- Trailing spaces are significant, so use the %TrimR function to remove them when necessary.
This subprocedure can be used to provide a subset feature for subfile programs or reports that don’t use embedded SQL. Creating simple subprocedures such as LIKE can quickly pay off by adding powerful functionality to any number of programs.
Michael Sansoterra is a programmer/analyst for i3 Business Solutions, an IT services firm based in Grand Rapids, Michigan. Click here to contact Michael Sansoterra by e-mail.