Tuesday, June 3, 2014

How to right justify a alphanumeric field with leading zeroes

%trim %xlate %editc

I was asked a question, via Facebook, on how I would take an alphanumeric field that contains '1 ' (1-blank-blank) and convert it to '001'.

Before I had time to answer the question others had posted their ideas:

  • Convert the field to numeric and then convert it back to alphanumeric with the edit code X.
  • Use an array to check and move each element, no example code was given.

While both would work, I came up with what I consider an easier/more efficient way.

Scenario 1

But first, many people gave roughly the same example where they would move the value of the first alphanumeric field, Fld1, into a numeric field, Nbr, and then moved the numeric value back into the second alphanumeric field, Fld2, see below:

01  dcl-s Fld1 char(3) inz('1') ;
02  dcl-s Fld2 like(Fld1) ;
03  dcl-s Nbr int(3) ;

04  Nbr = %int(Fld1) ;
05  Fld2 = %editc(Nbr:'X') ;

I have defined the two alphanumeric fields and the one numeric/integer field in lines 1 – 3.

On line 4 I convert the value in Fld1 to a number using the 'Convert to Integer' built in function, %INT.

On line 5 I take the number/integar and convert it to the alphanumeric field, Fld2, using the 'Edit Value using a Editcode' built in function, %EDITC. Using edit code X means that there is no formatting, therefore, the value '001' is moved to Fld2.

Scenario 2

None of the other posters mentioned that I could combine lines 4 and 5 into one line, see below:

04  evalr Fld2 = %editc(%int(Fld1):'X') ;

Notice how I have to use the EVALR, evaluation with right adjust, operation code. The temporary value generated by this line is 4 alphanumeric, and contains '0001'. Without the EVALR Fld2 would contain '000', as the trailing '1' would be lost. By using the EVALR the leading '0' is dropped, and Fld2 contains '001'.

Scenario 3

In my opinion it is more efficient, and less resource intensive, not to convert alphanumeric values to numbers and back again. I would leave the values as alphanumeric and do the following:

04 evalr Fld2 = %trim(Fld1) ;
05 Fld2 = %xlate(' ':'0':Fld2) ;

On line 4 I remove leading and trailing character using the 'Trim' built in function, %TRIM. I have used the %TRIM, rather than the %TRIML or %TRIMR, as it removes both the leading and trailing spaces, "trimming" '1 ' (1-blank-blank), ' 1 ' (blank-1-blank), and ' 1' (blank-blank-1) to '1'. The EVALR rights adjusts, therefore, Fld2 contains ' 1' (blank-blank-1).

One line 5 I use the 'Translate' built in function, %XLATE, to convert any blanks to zeroes. The result is '001'.

Scenario 4

I have Anonymous and Brian Rusch to thank for Scenario 4. It is the simplest method::

04 evalr Fld2 = '000' + %trim(Fld1) ;

It is so simple I do not think that it needs any explantion.

I would like to thank Anonymous and Brian for their contribution. And I would like to remind you that if you do post comments, etc., please include your name so I can give credit where it is due.

Comparison

The only way I can think of determining which method is the best is which scenario takes less time to execute. Therefore, I ran each scenario 10 million times and determined how many microseconds it took to run. I did this 5 times and the average time, in microseconds, for each scenario is as follows:

 Scenario 1   Scenario 2   Scenario 3   Scenario 4 
6857600 6880400 5689000 4372600

What can we tell from this?

By all means we are dealing in microseconds, which is one millionth of a second, so the time difference is very small. It was is not a suprise that the simplest, Scenario 4, was by far the fastest. The first two scenarios show what a performance hit it is converting from one data type to another and back again, alphanumeric to numeric to alphanumeric.

As a friend always reminds me: K.I.S.S., "Keep It Simple Stupid".

 

Do you know of a better way? If you do rather than post it in the comments, below, please send it to me using the Contact Form on the right. That way I can format it properly and give you credit for it.

 

You can learn more about these built in functions from the IBM web site:

 

This article was written for IBM i 7.1, and it should work with earlier releases too.

2 comments:

  1. EvalR fld1 = '000' + %trim(fld1)

    ReplyDelete
  2. I don't know if it's a better way, but another way is to concatenate a constant of all zeroes to the trimmed string and right adjust when you assign to the variable:

    dcl-c allzeros '0000000000';
    // adjust number of zeroes as necessary

    EvalR Fld2 = allzeros + %trim(Fld1) ;

    ReplyDelete

To prevent "comment spam" all comments are moderated.
Learn about this website's comments policy here.

Some people have reported that they cannot post a comment using certain computers and browsers. If this is you feel free to use the Contact Form to send me the comment and I will post it for you, please include the title of the post so I know which one to post the comment to.