Using RPGLE to extract invoice numbers from an alpha string

IBM i

Feb 26

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?

Follow

About the Author

IBM i Software Developer, Digital Dad, AS400 Anarchist, RPG Modernizer, Alpha Nerd and Passionate Eater of Cheese and Biscuits. Nick Litten Dot Com is a mixture of blog posts that can be sometimes serious, frequently playful and probably down-right pointless all in the space of a day. Enjoy your stay, feel free to comment and in the words of the most interesting man in the world: Stay thirsty my friend.

  • Jan says:

    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

  • >