ABAP String Processing: CONCATENATE, && and STRLEN
String handling in ABAP has evolved significantly over the years. Understanding the difference between
STRING and CHAR(n) types, and knowing
both legacy and modern syntax, is essential for writing correct and maintainable ABAP code.
This guide covers the most common string operations with runnable examples.
The short answer
- Join strings with
lv_a && ` ` && lv_bor a string template|{ lv_a } { lv_b }|. - A blank written as
' 'disappears; write it as` `(backquotes) instead. Why CONCATENATE a b INTO c SEPARATED BY space.inserts one blank.strlen( lv )returns the length, ignoring the padding of aCHARfield.
String Types in ABAP
ABAP has two fundamentally different string types: STRING is a dynamic-length
heap-allocated string, while CHAR(n) is a fixed-length character field stored
inline. Using STRING where CHAR(n) is expected
(e.g. a database field) causes implicit conversions and potential truncation bugs.
Choose the type that matches your use case and the target field definition.
" Fixed-length: padded with blanks to the declared length
DATA lv_char TYPE c LENGTH 20. " or: CHAR20 / char20
lv_char = 'Hello'. " stored as 'Hello '
" Dynamic-length: no padding, heap-allocated
DATA lv_string TYPE string.
lv_string = 'Hello'. " stored as 'Hello' (5 chars)
Concatenation with && and String Templates
Since ABAP 7.02, you can use the && operator to concatenate strings inline,
much like + in Python or Java. This is more readable than the legacy
CONCATENATE statement and works naturally in assignments and expressions.
String templates with |...| syntax are often clearer still, because the blanks
you type between the braces are exactly the blanks you get.
DATA: lv_first TYPE string VALUE 'John',
lv_last TYPE string VALUE 'Doe',
lv_result TYPE string.
" Using && with a `string literal` (backquotes keep the blank)
lv_result = lv_first && ` ` && lv_last.
WRITE: / lv_result. " John Doe
" Using a string template (usually the clearest)
lv_result = |{ lv_first } { lv_last }|.
WRITE: / lv_result. " John Doe
Note the backquotes around the blank. The version almost everyone writes first,
lv_first && ' ' && lv_last, prints JohnDoe.
Why the Space Disappears: ' ' vs ` `
ABAP has two kinds of literal. '...' is a text field literal: it has the
fixed-length type c, and trailing blanks in a c value
are treated as padding, not content. So when it is used in a string expression or as a
CONCATENATE operand, ' ' contributes nothing at all.
`...` is a string literal of type string,
and every character in it, blanks included, is kept.
The separator of CONCATENATE ... SEPARATED BY is the exception: its blanks are kept,
which is why SEPARATED BY space works.
REPORT zspace_gotcha.
DATA: lv_first TYPE string VALUE 'John',
lv_last TYPE string VALUE 'Doe',
lv_result TYPE string.
" 'text field literal': the trailing blank is dropped
lv_result = lv_first && ' ' && lv_last.
WRITE: / lv_result. " JohnDoe
" `string literal`: the blank is kept
lv_result = lv_first && ` ` && lv_last.
WRITE: / lv_result. " John Doe
" CONCATENATE drops it from an operand too...
CONCATENATE lv_first ' ' lv_last INTO lv_result.
WRITE: / lv_result. " JohnDoe
" ...but not from the separator
CONCATENATE lv_first lv_last INTO lv_result SEPARATED BY space.
WRITE: / lv_result. " John Doe
This is also one of the most common mistakes in AI-generated ABAP: models write
' ' because that is how a space is written in most other languages.
CONCATENATE Statement
The CONCATENATE statement joins multiple strings into a target variable
and optionally inserts a separator with SEPARATED BY.
You will encounter this pattern frequently in existing ABAP codebases, so knowing how to read it is important.
For new code, prefer the && operator or string templates instead.
DATA: lv_city TYPE string VALUE 'Tokyo',
lv_country TYPE string VALUE 'Japan',
lv_result TYPE string.
" Plain CONCATENATE: operands are joined with nothing in between
CONCATENATE lv_city lv_country INTO lv_result.
WRITE: / lv_result. " TokyoJapan
" SEPARATED BY: the separator keeps its blanks
CONCATENATE lv_city lv_country INTO lv_result SEPARATED BY ', '.
WRITE: / lv_result. " Tokyo, Japan
" SEPARATED BY space: the classic way to insert one blank
CONCATENATE lv_city lv_country INTO lv_result SEPARATED BY space.
WRITE: / lv_result. " Tokyo Japan
Try CONCATENATE in ABAP Dojo →
RESPECTING BLANKS
Operands of fixed-length types (c, n,
d, t) lose their trailing blanks when concatenated.
Add RESPECTING BLANKS when the padding matters, for example when building
fixed-width file records.
DATA: lv_code TYPE c LENGTH 6 VALUE 'AB',
lv_result TYPE string.
" Fixed-length fields lose their padding by default
CONCATENATE lv_code 'X' INTO lv_result.
WRITE: / lv_result. " ABX
" RESPECTING BLANKS keeps the full field length
CONCATENATE lv_code 'X' INTO lv_result RESPECTING BLANKS.
WRITE: / lv_result. " AB X
CONCATENATE LINES OF an Internal Table
To join every line of an internal table, use CONCATENATE LINES OF, or the
concat_lines_of( ) function when you want an expression.
Without sep, concat_lines_of( ) joins the lines
with nothing in between.
DATA: lt_parts TYPE STANDARD TABLE OF string WITH EMPTY KEY,
lv_result TYPE string.
APPEND `red` TO lt_parts.
APPEND `green` TO lt_parts.
APPEND `blue` TO lt_parts.
" Statement form
CONCATENATE LINES OF lt_parts INTO lv_result SEPARATED BY `, `.
WRITE: / lv_result. " red, green, blue
" Expression form (ABAP 7.02+)
lv_result = concat_lines_of( table = lt_parts sep = `, ` ).
WRITE: / lv_result. " red, green, blue
String Length with STRLEN( )
strlen( ) returns the number of characters in a string. It is the standard function
for getting string length in ABAP and works on both STRING and
CHAR(n) types. ABAP keywords and built-in functions are not case-sensitive, so
STRLEN( ) and strlen( ) are the same call.
Note the blanks inside the parentheses: strlen(lv_text) without them is a syntax error.
DATA: lv_text TYPE string VALUE 'Hello, ABAP!',
lv_length TYPE i.
lv_length = strlen( lv_text ).
WRITE: / 'Length:', lv_length. " Length: 12
" Useful for conditional checks
IF strlen( lv_text ) > 10.
WRITE: / 'String is longer than 10 characters.'.
ENDIF.
STRLEN and trailing blanks
What strlen( ) counts depends on the type. For a CHAR
field, the padding is not counted, so a c LENGTH 10 field holding
'Hi' has length 2, not 10. For a STRING, trailing
blanks count, but only if they made it into the string in the first place.
DATA: lv_char TYPE c LENGTH 10 VALUE 'Hi',
lv_string TYPE string,
lv_length TYPE i.
" CHAR field: trailing padding is not counted
lv_length = strlen( lv_char ).
WRITE: / 'CHAR(10):', lv_length. " CHAR(10): 2
" STRING from a `string literal`: trailing blanks count
lv_string = `Hi `.
lv_length = strlen( lv_string ).
WRITE: / 'string:', lv_length. " string: 4
" STRING from a 'text field literal': the blanks were dropped on assignment
lv_string = 'Hi '.
lv_length = strlen( lv_string ).
WRITE: / 'from literal:', lv_length. " from literal: 2
Case Conversion with TRANSLATE
The TRANSLATE statement converts a string to upper or lower case in place.
It modifies the variable directly rather than returning a new value, which is a common gotcha for developers
coming from other languages. For read-only conversions without side effects, use the
to_upper / to_lower string functions.
DATA lv_text TYPE string VALUE 'Hello World'.
" TRANSLATE modifies the variable in place
TRANSLATE lv_text TO UPPER CASE.
WRITE: / lv_text. " HELLO WORLD
TRANSLATE lv_text TO LOWER CASE.
WRITE: / lv_text. " hello world
" Expression-style alternative, no side effects
DATA lv_upper TYPE string.
lv_upper = to_upper( lv_text ).
WRITE: / lv_upper. " HELLO WORLD
WRITE: / lv_text. " hello world (unchanged)
Full Example
This example combines the core operations from this guide: &&, string templates, strlen( ), to_upper( ) and CONCATENATE. Open it in ABAP Dojo and click Run to see each technique in action.
REPORT zstring_processing.
DATA: lv_first TYPE string VALUE 'John',
lv_last TYPE string VALUE 'Doe',
lv_full TYPE string,
lv_quoted TYPE string,
lv_length TYPE i,
lv_upper TYPE string,
lv_city TYPE string VALUE 'Berlin',
lv_country TYPE string VALUE 'Germany',
lv_location TYPE string.
" Concatenation with && (backquotes keep the blank)
lv_full = lv_first && ` ` && lv_last.
WRITE: / 'Full name:', lv_full.
" The same with ' ' loses the blank
lv_quoted = lv_first && ' ' && lv_last.
WRITE: / 'With quotes:', lv_quoted.
" String template
WRITE: / |Hello, { lv_full }!|.
" Length
lv_length = strlen( lv_full ).
WRITE: / 'Name length:', lv_length.
" Upper case
lv_upper = to_upper( lv_full ).
WRITE: / 'Upper case:', lv_upper.
" Legacy CONCATENATE with SEPARATED BY
CONCATENATE lv_city lv_country INTO lv_location SEPARATED BY ', '.
WRITE: / 'Location:', lv_location.