This morning my nerdish IBM-i Chum Toby, pinged me a whatsapp challenge to write a little RPG code snippet to “extract invoice numbers” from a random string of data.
So…. if you had a string ‘INV#10563592 DATED 12/17/19 SO#286045 NOT GOING’ and you knew that this is a shitty text file way of referencing an invoice to a sales order. What %BIF would you to extrapolate ‘10563592’. Invoices are all numeric, 8 digits and it’s a good bet will be preceded by by ‘INV#’
Toby. He swears a lot. This was particularly mild.
To look for invoice numbers – we can use the %SCAN %BIF
%SCAN returns the first position of the search argument in the source string, or 0 if it was not found. If the start position is specified, the search begins at the starting position. The result is always the position in the source string even if the starting position is specified.
To test the suspected invoice numbers – we can use %CHECK
%CHECK returns the first position of the string containing a character. The check begins at the starting position and continues to the right until a character that is not contained in the search string is found.
To extract invoice numbers – we can use %SUBST
%SUBST returns a portion of argument string. It may also be used as the result of an assignment with the EVAL operation code. The start parameter represents the starting position of the substring. The length parameter represents the length of the substring.
Sample RPGLE sub-procedure
So taking the premise that we can check for a number like this:
You can use this to test numeric w/o indicators.
dcl-s Numbers char(10) Inz('0123456789') If %check(Numbers:My_Field) > 0; Error = *On; // it has non-numerics in it else; Error = *off; // everything is numeric #huzzah! EndIf;
Let’s knock out a little code snippet to try to do this:
// + ------------------------------------------------------- + // + Extract Invoice Number from string + // + ------------------------------------------------------- + dcl-proc get_invoice_from_string; dcl-pi get_invoice_from_string char(8); p_string char(100) const; end-pi; dcl-s success ind; dcl-s invoice char(8); dcl-s numbers char(10) Inz('0123456789'); dcl-s posn zoned(5); // Look for an invoice number starting with INV# first posn = %scan('INV#':p_string); // if this scan worked then 'posn' holds the starting character of 'INV#' if posn > 0; // now lets check if the next 8 chars are numeric If %check(numbers:%subst(p_string:posn+4:8)) > 0; success = *off; // it has non-numerics in it else; success = *on; // everything is numeric #huzzah! invoice = %subst(p_string:posn+4:8); EndIf; endIf; return invoice; end-proc;
and to call the procedure we would have something like this:
invoice_number = get_invoice_from_string( $stringtobescanned );
How does that work Tobers?
Got any better code snippets to do this?
Hi.
Maybe its more simple to use sql (in a rpg program) 🙂
regexp_substr extracts hits 🙂
select regexp_substr(regexp_substr(textfelt,’INV#.*[0-9]{8} ‘,1,1,’i’) , ‘[0-9]{8} ‘,1,1,’i’)
from (select ‘INV#05635902 DATED 12/17/19 SO#286045 NOT GOING’ as textfelt
from sysibm.sysdummy1);
Which would give a rpg program like this :
exec sql Value(regexp_substr(regexp_substr(:stringtobescanned,’INV#.*[0-9]{8} ‘,1,1,’i’) , ‘[0-9]{8} ‘,1,1,’i’) into :result;
Iam not a regex expert, but iam sure that a regex could be written that would match all combinations.
Best regards Jan