Skip to Content
Technical Articles
Author's profile photo B. Meijs

Using New ABAP stuff – new options for Strings

After my previous blog about the option of using Method Chaining (Using New ABAP stuff – Method Chaining and CL_SALV_TABLE) I thought it would be a good idea to write something about my experiences with new string options like String Templates, Chaining of strings, and built-in string functions. Just as with Method Chaining, using these string options allow for making ABAP code terser, which means that fewer statements are needed for the same functionality, without compromising readability of the code.

What’s it al about?

Several new options for the handling of characters strings were introduced to ABAP in WAS702:

  • String Templates: the option to create a character string out of literal texts, expressions, and control characters.
  • Chaining Operator: chain two character-like operands into one new character string.
  • Character String Functions: built-in functions for searching, processing and comparing strings.

I will first explain these options and give a few examples. The last paragraph explains how the use of string templates, combined with built-in functions and the use of functional methods, limits the number of needed ABAP statements.

Note that the ABAP Keyword documentation contains several built-in examples, related to old and new ABAP features. These examples can be executed and debugged and its code can be analysed. Moreover, the program DEMO_EXPRESSIONS offers 45 examples of character string and byte string processing.

 

String Templates

The purpose of a string template is to create a new character string out of literal texts and embedded expressions. It largely replaces the use of the WRITE TO statement, which will be explained later on.

A string template is defined by using the | (pipe) symbol at the beginning and end of a template.

DATA: character_string TYPE string.
character_string = |This is a literal text.|.

This example has in fact exactly the same result as:

character_string = `This is a literal text.`.

The added value of a string template becomes clear when combining literal texts with embedded expressions and control characters. Embedded expressions are defined within a string template with curly brackets { expression }.  Note that a space between bracket and expression is obligatory.

An expression can be a data object (variable), a functional method, a predefined function or a calculation expression. Some examples are:

character_string = |{ a_numeric_variable }|.

character_string = |This resulted in return code { sysubrc }|.

character_string = |The length of text element 001 ({ text001 }) is { strlen( text001 ) }|.

 

Embedded expressions have a default output format, but also several formatting options, comparable to the format options of the WRITE statement. Some examples are:

DATA: amount_field   TYPE vbapnetwr VALUE ‘1234567.123’,
currency_field TYPE vbapwaerk.
character_string = |{ amount_field CURRENCY = currency_field  NUMBER = USER }|.
character_string = |{ amount_field COUNTRY = ‘GB ‘ }|.

 

Two limitations for which I haven’t found a solution yet are:

1) I could not find a formatting option for Conversion Exits. Consider the example below: the WRITE….TO… calls the conversion exit KONPD that converts an internal project number to an external project id. The string template inserts the internal project number into the string.

DATA: project_number TYPE projpspnr.
SELECT SINGLE pspnr FROM proj INTO project_number .
WRITE project_number TO character_string2.

character_string = |{ project_number }|.

 

2) The following option for text-elements is not supported in an embedded expression:

WRITE : ‘This is a text’(001).

 

The only option to use a numbered text is in an embedded expression:

character_string = |{ text001 }|.

 

However, using the Chaining Operator offers a simple solution for this as is demonstrated below.

Chaining Operator

The Chaining Operator && can be used to create one character string out of multiple other strings and string templates. The use of the chaining operator largely replaces the CONCATENATE statement.

In this example, a number text, a space, an existing character string and a new string template are concatenated into a new character string.

character_string  ‘Text literal’(002) && ` ` && character_string && |{ amount_field NUMBER = USER }|.

Built-in functions

SAP has added several new built-in functions for searching, comparing, and processing character strings.  A few of these functions already existed before release WAS702, like for example, CHARLEN( ) or STRLEN( ). Other statements like FIND, REPLACE or TRANSLATE can now be replaced by built-in functions Also new functions have been added.

Note that these built-in functions can be used as part of string templates or in operand positions. In the ABAP keyword documentation, the added value of these functions is described as followed:

The string functions enable many string processing tasks to be done in operand positions where previously separate statements and auxiliary variables were required.

 

A few examples of built-in functions are:

string_result = to_mixed( val = string_field sep = ` ` ).
string_result = reverse( string_field ).
distance_between_strings = distance( val1 = string_field val2 = string_result ).

 

The functions to_mixed and reverse speak for themselves. The function distance is a similarity function that calculates the minimum number of steps needed to change one string into another string, the so called Levenshtein distance. I’m still looking for an opportunity to use it in one of my customer assignments 😉

 

Compacting ABAP code by using new string options

Imagine that you have to create a tab-delimited file from an internal table with a line type, consisting of character and numeric type fields. Furthermore, you want the date and amount fields to be converted into a specific output format in the file.

The definition of the internal table could look like this:

TYPES: BEGIN OF ty_struct,
change_date   TYPE d,
amount        TYPE bf_dmbtr,”numeric type
currency_key  TYPE waers,
text_field    TYPE string,
END OF ty_struct.

Let us focus on the creation of one tab-delimited file entry. Pre-WAS702, this would look like this:

DATA: date_as_a_string TYPE c LENGTH 10,
amount_as_a_string TYPE c LENGTH 20.

WRITE <input_line>change_date TO date_as_a_string .
WRITE <input_line>amount      TO amount_as_a_string CURRENCY input_line>currency_key.
CONCATENATE date_as_a_string
amount_as_a_string
<input_line>currency_key
<input_line>text_field INTO download_line
SEPARATED BY cl_abap_char_utilities=>horizontal_tab.

Note that you need two variables and two WRITE TO statements to convert the date and amount field to a suitable output format. Using the amount field, which is a numeric field, directly in the CONCATENATE statement will lead to a syntax error.

Using a string template, chaining operator and control characters, these 5 statements can be reduced to only one statement:

download_line =
|{ <input_line>change_date DATE = USER }\t| &&
|{ <input_line>amount NUMBER = USER CURRENCY = <input_line>currency_key }\t| &&
|{ <input_line>currency_key }\t{ <input_line>text_field } |.

The tab delimiter is inserted by using the control character \t.

This is just one of many examples that I can think of.  Just consider the following snippets of code and consider the number of intermediate steps your would need to implement this functionality without string templates.

* Include a built-in function

log_information = |Number of entries in download: { lines( download_file ) } |.

* Include a functional method call

log_information = |My IP address = { cl_gui_frontend_services=>get_ip_address( ) }|.

Conclusion

In my daily life as an ABAP programmer, I’m working on customer SAP systems with basis versions ranging from R/3 4.6C up to WAS731 based systems. Not being able to use new string options on several older customer systems can be quite frustrating after having used them on other systems. I once fell into the trap of writing a program using string templates and method chaining. I then tried to install this program on another ECC60 system, but this failed because this system was based on WAS701. I had to rewrite parts of the program: define new intermediate variables, call intermediate methods to get values, and use the WRITE TO statement to get the proper date and amount values in my download.

So, if you’re working on a WAS702vv-based system, I would advice you to start using new ABAP possibilities because they will improve your speed of development and make your programs better maintainable. For me, I just enjoy discovering and trying new options and share my experiences with other programmers.

Assigned Tags

      21 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Narin Nandivada
      Narin Nandivada

      Very informative. Thanks.

      Author's profile photo B. Meijs
      B. Meijs
      Blog Post Author

      Thanks for that.

      Author's profile photo Former Member
      Former Member

      Hi,

      Thanks to provide the document with your example codes...

      Perfect.... All The best... 🙂

      Regards,

      Ragav

      Author's profile photo Former Member
      Former Member

      Thanks for giving code with good examples

      Author's profile photo Former Member
      Former Member

      Good blog.

      To get around the limitation of the lack of conversion exits, you could do the following:

      Create a static functional method that wraps up the required conversion exit.

      Embed this new method into the expression.

      For example, outputing a Sales Order number formatted by the ALPHA routine:

      character_string = |Your Order Number is { zcl_myclass=>alpha( pv_vbeln ) }|.

      The only thing I don't like about this is that the Returning parameter of the method cannot have a generic type (such as C), so in order to make it usable for VBELN, MATNR etc. with different lengths, you have to type the parameter as something explicit like CHAR20.

      Regards,

      Pete

      Author's profile photo Christian Guenter
      Christian Guenter

      The only thing I don't like about this is that the Returning parameter of the method cannot have a generic type (such as C), so in order to make it usable for VBELN, MATNR etc. with different lengths, you have to type the parameter as something explicit like CHAR20.

      Why not using String as type of the returning parameter?

      Author's profile photo Former Member
      Former Member

      Yes that would do the job too

      Author's profile photo François Henrotte
      François Henrotte

      Now you can use a format to convert your value to internal or external formatting :

      character_string = |Your Material Number is { pv_matnr ALPHA = IN }|.    "Adds leading zeros
      character_string = |Your Material Number is { pv_matnr ALPHA = OUT }|.   "Removes leading zeros

       

      Author's profile photo Former Member
      Former Member

      very useful!

      Thanks!

      Author's profile photo Henning Schindler
      Henning Schindler

      Be careful with different datatypes. You can use string chaning on numeric Textfield together with a string. During runtime the string will be ignored and you do not get a runtimeerror.

      Example:

      "build in datatype n --> Numeric text field
      DATA: numeric TYPE n LENGTH 6 VALUE '201607'.

               numeric = numeric+4(2) && '.' && numeric(4).
               "Result: 072016
               WRITE: numeric.

      Author's profile photo Aasim Khan
      Aasim Khan

      Wow, that's plethoric! But how would you concatenate two variables keeping blanks?

      Old school way would be ->

      CONCATENATE lv_string1 lv_string2 INTO lv_string3 RESPECTING BLANKS.

      Author's profile photo Former Member
      Former Member

      For short: they are always respecting blanks. Taking your example the result could look like this:

      lv_string3 = |{ lv_string1 } { lv_string2 }|.

      Importand is only the space between the closing bracket of our first field and the opening bracket of the next.

      Author's profile photo Denis Skuridin
      Denis Skuridin

      And what if we have fields like char20? See no formatting option  or smth similar to achieve this without CONCATENATE.

      Author's profile photo Nigel James
      Nigel James

      Thanks for a great blog. I sent some colleagues this way to see all your cool examples.

      The word distance is interesting - I have seen soundex used as a proxy for searching and getting hitrs on words thet approximage whet ehty are meening.

      https://stackoverflow.com/a/473554/2434654

      Author's profile photo Sandra Rossi
      Sandra Rossi

      You indicate that the following statement is not accepted but it is (at least it works in 7.52) :

      DATA(var) = |{ 'this is a text'(001) }|.

      Author's profile photo B. Meijs
      B. Meijs
      Blog Post Author

      Thank you for your reply. You are absolutely true. After having posted this blog (2013) I have used the option you describe very often.

      Author's profile photo Bärbel Winkler
      Bärbel Winkler

      B. Meijs

      A rather belated thanks for this neat summary which I only happened upon today – but I guess, better late than never ?! I found your blog post while searching for a solution of how to best create a concatenated string.

      I wanted to use the CleanCode way to assemble a text string in order to initialize the content for a selection-screen value containing ‘*’ for a pattern search:

      s_agrn[] = VALUE #( ( option = 'EQ' sign = 'I' low = |* { usergroup } *| ) ).

      If USERGROUP contains ‘XXXX’ the resulting value for LOW is ‘* XXXX *’, so spaces are automatically introduced which I obviously don’t want to have in this case and wouldn’t get if I simply used the tried and trusted CONCATENATE statement (without ‘separted by space’).

      I also don’t get spaces when I use what is shown as the “anti-pattern” in CleanCode, namely the chaining via &&:

      s_agrn[] = VALUE #( ( option = 'CP' sign = 'I' low = '*' && usergroup && '*' ) ).

      I read through the documentation but nothing really jumped out how I could suppress the unwanted spaces when I do it the “CleanCode way”. Is there one which I missed / didn’t recognize?

      I’m working in a NW 750 SP16 EHP8 system.

      Thanks much & Cheers

      Bärbel

      Author's profile photo Mike Pokraka
      Mike Pokraka

      Just leave out the spaces.

      string = |* { foo } *|.  "your example
      string = |*{ foo }*|.    "no spaces
      Author's profile photo Bärbel Winkler
      Bärbel Winkler

      Thanks, Mike! Wish I could remember when a space is needed and when not with the various syntax elements!

      Cheers

      Bärbel

      Author's profile photo Mike Pokraka
      Mike Pokraka

      Yes, it's all in the name of backwards compatibility, much of it due to to that ancient substring syntax to write string(5)+4

      So the space was introduced to distinguish substrings from parameters.

      Author's profile photo Sandro Engelbrecht
      Sandro Engelbrecht

      Does it make any difference when using accute accents ´ or apostrophes ' for strings?