Wednesday, January 14, 2015

Trim in CL and its Second Parameter

trim (%TRIM, %TRIMR,%TRIML) is now in CL. And did you know that there is a second parameter to state which characters you want trimmed?

I am sure I am not the only person who has been using the Trim built in functions (BIFs) in their RPG code to remove leading and trailing blanks from strings. Trim BIFs were introduced into CL with IBM i release 7.1, and function in the same way as their RPG brethren.

Were you aware that the Trim BIFs have a second parameter that can be used for removing characters other than blanks? I have Miguel Cordova to thank for bringing this to my attention. Using the second parameter I can remove any character using the Trim. Below I will show examples in RPG and in CL, and discuss what I found in using them in both languages.

The syntax for the RPG and CL BIFs are almost identical, the only difference being the use of the colon ( : ) to separate the two parameters in RPG.

I have used Trim (%TRIM), Trim Right (%TRIMR), and Trim Left (%TRIML) in my RPG code to remove leading and trailing spaces from fields I would be concatenating together:

  FullName = %trimr(FirstName) + ' ' + %trimr(LastName) ;

The equivalent in CL could be the following:

  CHGVAR   VAR(&FULLNAME) VALUE(%TRIMR(&FIRSTNAME) || +
             ' ' || %TRIMR(&LASTNAME))

Note: In CL I use the shortcuts || and |< in place of *CAT and *TCAT.

So what of this second parameter? If I am presented with a variable that contains a leading or trailing character, for example an asterisk ( * ), I want remove them and left justify the remainder of the string.

01  FirstName = '********John********' ;
02  LastName = '*********Doe********' ;

03  FullName = %trim(FirstName:'*') + ' ' +
               %trim(LastName:'*') ;       

The RPG code above shows that I have my first name in the variable FirstName, line 1, and my last name in LastName, line 2, both with leading and trailing asterisks.

As I have mentioned The Trim BIF (%TRIM, %TRIMR, %TRIML) has two parameters:

  • Name of variable or alphanumeric string.
  • Characters to replace. The default is blank, which is why we do not have give the second parameter if we are removing blanks.

In the example I have given above I want to remove all leading and trailing asterisks and then concatenate the two variables together into the variable FullName. The result is 'John Doe'.

The equivalent in CL could look like:

01  CHGVAR   VAR(&FIRSTNAME) VALUE('********John********')
02  CHGVAR   VAR(&LASTNAME) VALUE('*********Doe********')

03  CHGVAR   VAR(&FULLNAME) VALUE(%TRIM(&FIRSTNAME '*') || +
              ' ' || %TRIM(&LASTNAME '*'))

If I replace the first asterisk in the FirstName variable, see below, with a blank when the code is run the variable FullName will contain ' *******John Doe'.

01  FirstName = ' *******John********' ;
02  LastName = '*********Doe*********' ;

03  FullName = %trim(FirstName:'*') + ' ' +
               %trim(LastName:'*') ;       

The reason is that the second parameter of the BIF, 'Characters to replace', does not contain blank. If I add blank to the second parameters of the %TRIM BIFs on line 3, see below, then FullName will contain 'John Doe'.

01  FirstName = ' *******John********' ;
02  LastName = '*********Doe*********' ;

03  FullName = %trim(FirstName:'* ') + ' ' +
               %trim(LastName:'* ') ;       

The same applies if I would have replaced the last character in either FirstName or LastName with a blank.

I could make it really complicated (ridiculous) with a strings like this:

01  dcl-c InvalidCharacters ' ~!@#$%¢&*()_+{}|?' ;

02  FirstName = '!@#$%¢&John*()_+{}|?' ;
03  LastName = '?|}{+_)(*Doe&¢%$#@!~' ;

04  FullName = %trim(FirstName:'~!@#$%¢&*()_+{}|? ') + ' ' +
               %trim(LastName:InvalidCharacters) ;

You will notice on line 1 that I have defined a constant to contain a whole load of characters I would want to trim from my string. And on line 4 you can see that I have entered all the characters in the %TRIM for FirstName and use the constant with LastName.

In CL the equivalent could be:

01  DCL   VAR(&INVALID) TYPE(*CHAR) LEN(20) +
            VALUE('~!@#$%¢&*()_+{}|? ')

02  CHGVAR   VAR(&FIRSTNAME) VALUE('!@#$%¢&*John()_+{}|?~')
03  CHGVAR   VAR(&LASTNAME) VALUE('~!@#$%¢&*Doe()_+{}|? ')

04  CHGVAR   VAR(&FULLNAME) +
               VALUE(%TRIM(&FIRSTNAME &INVALID) +
                     || ' ' || %TRIM(&LASTNAME &INVALID))

 

You can learn more about these on the IBM website:

 

This article was written for IBM i 7.2, and it should work the 7.1 too.

14 comments:

  1. For whatever reason I never picked up on a second parm... good to know. Thanks

    ReplyDelete
  2. Cool! I never new this...

    ReplyDelete
  3. Unless I am going mad (quite possible), this isn't correct - it should be: ' *******John Doe')?

    If I replace the first asterisk in the FirstName variable, see below, with a blank when the code is run the variable FullName will contain ' *****John Doe'.

    01 FirstName = ' *******John********' ;
    02 LastName = '*********Doe*********' ;

    03 FullName = %trim(FirstName:'*') + ' ' +
    %trim(LastName:'*') ;

    Mike Collins

    ReplyDelete
    Replies
    1. Mike, you are right (and not going mad). Two asterisks were missing from the text. I have made the correction.
      Thanks

      Delete
    2. Thanks Simon - it doesn't detract from a very useful blog though. Now just need to get my organisation up to 7.1...

      Delete
  4. CL is getting more powerful and it's great.

    I'd like SNDPGMMSG to produce a message to the effect:

    The value for counter is &countc.

    With my code below, if the value is non-zero, it works fine by trimming off the leading zeroes. If the value is zero, it results in a blank.

    chgvar var(&countc) value(&count) /* cvt int to char */
    sndpgmmsg msgid(cpf9898) msgf(qcpfmsg) msgdta('The value for counter is ' *cat %triml(&countc '0'))

    I can't think of another way so for now, I am formatting &countc ahead of time by testing the value of &count; if 0, then &countc='0',
    else
    &countc=&count
    &countc=%triml(&countc '0')

    Then just trimming blanks in the sndpgmmsg command.

    Is there a better way?

    Thanks.

    ReplyDelete
  5. Nice write up however all the links to the IBM website are no longer functional

    ReplyDelete
  6. Cool! I learned something useful today! Thanks!

    ReplyDelete
  7. %len(%trim( ... )) doesn't work ... -.- IBM dislikes Programmer ...

    ReplyDelete
    Replies
    1. <dcl-s Var1 char(10) inz('12') ;
      dcl-s Length packed(2) ;

      Length = %len(Var1) ;
      dsply ('1: ' + %char(Length)) ;

      Length = %len(%trim(Var1)) ;
      dsply ('2: ' + %char(Length)) ;

      DSPLY 1: 10
      DSPLY 2: 2

      Works for me

      Delete
  8. @Simon Hutchinson
    Thank you for redirecting me to this post!. But i need to remove zeros in a string and keep it right justified. If I use trim will it be possible. Also my string variable length is 70 and I am not sure what kind of numeric as character wil l be fetched in that variable.
    Example:
    DVar1 S 72 varying
    Var1 = '00005'
    I need Var1 = '<><><><>5' (<> = Space making it right justified)

    ReplyDelete
    Replies
    1. I am guessing this is RPG if so use EVALR, which will right justify the result.

      Delete
  9. Great article, I used it to add a trailing slash to a folder name if needed.

    It’s not perfect ('/temp//' wouldn’t cause an error but silently replaced by '/temp/', but it’s ok for what I wanted.

    CHGVAR VAR(&FOLDER) VALUE(%TRIMR(&FOLDER' /') *tcat '/')

    Let me know if there’s a better way :-)

    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.