String Templates (auch Template-Strings) ermöglichen die elegante Erstellung von Strings mit eingebetteten Ausdrücken und Formatierungsoptionen. Sie werden mit |...| begrenzt und enthalten Ausdrücke in {...}.
Syntax
|Literaler Text { ausdruck } weiterer Text||{ ausdruck OPTION = wert }|Grundprinzip
- Text zwischen
|...|wird als String interpretiert {...}enthält Ausdrücke, die ausgewertet und eingefügt werden- Formatierungsoptionen steuern die Darstellung
- Escape-Sequenzen für Sonderzeichen:
\|,\{,\},\\,\n,\r,\t
Beispiele
1. Einfache Interpolation
DATA: lv_name TYPE string VALUE 'Max', lv_age TYPE i VALUE 30.
" Klassisch mit CONCATENATEDATA: lv_text TYPE string.CONCATENATE 'Hallo ' lv_name ', du bist ' lv_age ' Jahre alt.' INTO lv_text.
" Modern mit String TemplateDATA(lv_text2) = |Hallo { lv_name }, du bist { lv_age } Jahre alt.|.
WRITE: / lv_text2. " Hallo Max, du bist 30 Jahre alt.2. Ausdrücke in Templates
DATA: lv_a TYPE i VALUE 10, lv_b TYPE i VALUE 5.
" Berechnungen direkt einbettenDATA(lv_calc) = |{ lv_a } + { lv_b } = { lv_a + lv_b }|.WRITE: / lv_calc. " 10 + 5 = 15
" MethodenaufrufeDATA(lv_upper) = |Name: { to_upper( lv_name ) }|.WRITE: / lv_upper. " Name: MAX
" Konditionelle AusdrückeDATA(lv_status) = |Status: { COND #( WHEN lv_age >= 18 THEN 'Erwachsen' ELSE 'Minderjährig' ) }|.3. Zahlenformatierung (WIDTH, ALIGN, PAD)
DATA: lv_num TYPE i VALUE 42.
" Mindestbreite mit WIDTHDATA(lv_w) = |Nummer: { lv_num WIDTH = 10 }|.WRITE: / lv_w. " Nummer: 42
" Ausrichtung mit ALIGNDATA(lv_left) = |[{ lv_num WIDTH = 10 ALIGN = LEFT }]|.DATA(lv_right) = |[{ lv_num WIDTH = 10 ALIGN = RIGHT }]|.DATA(lv_center) = |[{ lv_num WIDTH = 10 ALIGN = CENTER }]|.
WRITE: / lv_left. " [42 ]WRITE: / lv_right. " [ 42]WRITE: / lv_center. " [ 42 ]
" Füllzeichen mit PADDATA(lv_padded) = |{ lv_num WIDTH = 6 ALIGN = RIGHT PAD = '0' }|.WRITE: / lv_padded. " 0000424. Dezimalzahlen formatieren (DECIMALS, SIGN)
DATA: lv_amount TYPE p DECIMALS 2 VALUE '-1234.56'.
" Dezimalstellen angebenDATA(lv_d1) = |Betrag: { lv_amount DECIMALS = 2 }|.WRITE: / lv_d1. " Betrag: -1234.56
" Vorzeichen-PositionDATA(lv_sign_left) = |{ lv_amount SIGN = LEFT }|. " -1234.56DATA(lv_sign_right) = |{ lv_amount SIGN = RIGHT }|. " 1234.56-DATA(lv_sign_leftplus) = |{ lv_amount SIGN = LEFTPLUS }|. " -1234.56 (+ bei positiv)
" TausendertrennzeichenDATA: lv_big TYPE p DECIMALS 2 VALUE '1234567.89'.DATA(lv_sep) = |{ lv_big NUMBER = USER }|. " Benutzerformat (z.B. 1.234.567,89)DATA(lv_raw) = |{ lv_big NUMBER = RAW }|. " Ohne Formatierung5. Datumsformatierung (DATE)
DATA: lv_date TYPE d VALUE '20241115'.
" Verschiedene DatumsformateDATA(lv_d_raw) = |{ lv_date DATE = RAW }|. " 20241115DATA(lv_d_iso) = |{ lv_date DATE = ISO }|. " 2024-11-15DATA(lv_d_user) = |{ lv_date DATE = USER }|. " BenutzerformatDATA(lv_d_env) = |{ lv_date DATE = ENVIRONMENT }|.
WRITE: / 'RAW:', lv_d_raw.WRITE: / 'ISO:', lv_d_iso.WRITE: / 'USER:', lv_d_user.6. Zeitformatierung (TIME)
DATA: lv_time TYPE t VALUE '143025'.
" Verschiedene ZeitformateDATA(lv_t_raw) = |{ lv_time TIME = RAW }|. " 143025DATA(lv_t_iso) = |{ lv_time TIME = ISO }|. " 14:30:25DATA(lv_t_user) = |{ lv_time TIME = USER }|. " Benutzerformat
WRITE: / 'Uhrzeit:', lv_t_iso.7. Timestamp formatieren (TIMESTAMP)
DATA: lv_ts TYPE timestamp.GET TIME STAMP FIELD lv_ts.
DATA(lv_ts_iso) = |{ lv_ts TIMESTAMP = ISO }|.DATA(lv_ts_space) = |{ lv_ts TIMESTAMP = SPACE }|.DATA(lv_ts_user) = |{ lv_ts TIMESTAMP = USER }|.
WRITE: / 'Timestamp:', lv_ts_iso.8. Alpha-Konvertierung (ALPHA)
DATA: lv_matnr TYPE string VALUE '000000000000012345'.
" Alpha OUT: Führende Nullen entfernenDATA(lv_without_zeros) = |{ lv_matnr ALPHA = OUT }|.WRITE: / lv_without_zeros. " 12345
" Alpha IN: Führende Nullen hinzufügenDATA: lv_short TYPE string VALUE '12345'.DATA(lv_with_zeros) = |{ lv_short ALPHA = IN WIDTH = 18 }|.WRITE: / lv_with_zeros. " 0000000000000123459. Case-Konvertierung (CASE)
DATA: lv_text TYPE string VALUE 'Hallo Welt'.
DATA(lv_upper) = |{ lv_text CASE = UPPER }|. " HALLO WELTDATA(lv_lower) = |{ lv_text CASE = LOWER }|. " hallo weltDATA(lv_raw) = |{ lv_text CASE = RAW }|. " Hallo Welt
WRITE: / lv_upper.WRITE: / lv_lower.10. Escape-Sequenzen
" Sonderzeichen escapenDATA(lv_pipe) = |Pipe: \| und geschweifte Klammer: \{ \}|.DATA(lv_newline) = |Zeile 1\nZeile 2|.DATA(lv_tab) = |Spalte1\tSpalte2|.DATA(lv_backsl) = |Pfad: C:\\Ordner\\Datei|.
WRITE: / lv_pipe.WRITE: / lv_newline.WRITE: / lv_tab.11. Mehrzeilige String Templates
" Strings können über mehrere Zeilen gehenDATA(lv_multi) = |Dies ist ein | && |mehrzeiliger | && |String.|.
" Oder mit \n für tatsächliche ZeilenumbrücheDATA(lv_lines) = |Zeile 1\n| && |Zeile 2\n| && |Zeile 3|.
cl_demo_output=>display( lv_lines ).12. Kombination mit COND und SWITCH
DATA: lv_status TYPE i VALUE 2.
DATA(lv_msg) = |Status: { SWITCH string( lv_status WHEN 1 THEN 'Neu' WHEN 2 THEN 'In Bearbeitung' WHEN 3 THEN 'Abgeschlossen' ELSE 'Unbekannt') }|.
WRITE: / lv_msg. " Status: In Bearbeitung13. Strukturfelder einbetten
TYPES: BEGIN OF ty_customer, id TYPE i, name TYPE string, city TYPE string, END OF ty_customer.
DATA: ls_customer TYPE ty_customer.
ls_customer = VALUE #( id = 1001 name = 'Müller GmbH' city = 'Berlin' ).
DATA(lv_info) = |Kunde { ls_customer-id }: { ls_customer-name } aus { ls_customer-city }|.
WRITE: / lv_info. " Kunde 1001: Müller GmbH aus Berlin14. Tabellenzugriff in Templates
DATA: lt_names TYPE TABLE OF string.
lt_names = VALUE #( ( `Anna` ) ( `Bernd` ) ( `Clara` ) ).
" Direkter TabellenzugriffDATA(lv_first) = |Erster Eintrag: { lt_names[ 1 ] }|.WRITE: / lv_first. " Erster Eintrag: Anna
" Mit OPTIONAL für sichere ZugriffeDATA(lv_safe) = |Eintrag: { VALUE #( lt_names[ 999 ] OPTIONAL ) }|.15. String Templates in Schleifen
LOOP AT lt_names INTO DATA(lv_name). DATA(lv_line) = |{ sy-tabix }. { lv_name }|. WRITE: / lv_line.ENDLOOP.
" Ausgabe:" 1. Anna" 2. Bernd" 3. Clara16. String Templates für SQL
" Dynamisches SQL zusammenbauen (Vorsicht: SQL Injection!)DATA: lv_field TYPE string VALUE 'CARRID', lv_value TYPE string VALUE 'LH'.
" Besser: Parameter verwenden statt String-Konkatenation für SQL17. Formatierungsoptionen kombinieren
DATA: lv_price TYPE p DECIMALS 2 VALUE '1234.50'.
DATA(lv_formatted) = |Preis: { lv_price DECIMALS = 2 SIGN = LEFT WIDTH = 12 ALIGN = RIGHT PAD = ' '} EUR|.
WRITE: / lv_formatted. " Preis: 1234.50 EUR18. XSD-Format für Boolean
DATA: lv_flag TYPE abap_bool VALUE abap_true.
" XSD-Format: true/false statt X/''DATA(lv_xsd) = |Aktiv: { xsdbool( lv_flag ) }|.WRITE: / lv_xsd. " Aktiv: X
" Eigene DarstellungDATA(lv_custom) = |Aktiv: { COND #( WHEN lv_flag = abap_true THEN 'Ja' ELSE 'Nein' ) }|.Formatierungsoptionen Übersicht
| Option | Werte | Beschreibung |
|---|---|---|
WIDTH | Zahl | Mindestbreite |
ALIGN | LEFT, RIGHT, CENTER | Ausrichtung |
PAD | Zeichen | Füllzeichen |
CASE | UPPER, LOWER, RAW | Groß-/Kleinschreibung |
SIGN | LEFT, RIGHT, LEFTPLUS, RIGHTPLUS | Vorzeichenposition |
DECIMALS | Zahl | Dezimalstellen |
NUMBER | RAW, USER, ENVIRONMENT | Zahlenformat |
DATE | RAW, ISO, USER, ENVIRONMENT | Datumsformat |
TIME | RAW, ISO, USER, ENVIRONMENT | Zeitformat |
TIMESTAMP | ISO, SPACE, USER | Timestamp-Format |
ALPHA | IN, OUT, RAW | Alpha-Konvertierung |
CURRENCY | Währungscode | Währungsformat |
COUNTRY | Ländercode | Länderformat |
Vergleich: Klassisch vs. String Templates
" === KLASSISCH ===DATA: lv_result TYPE string.
CONCATENATE 'Kunde' ls_customer-id ':' ls_customer-name INTO lv_result SEPARATED BY space.
" Oder mit &&lv_result = 'Kunde ' && ls_customer-id && ': ' && ls_customer-name.
" === MODERN MIT STRING TEMPLATES ===DATA(lv_result2) = |Kunde { ls_customer-id }: { ls_customer-name }|.Wichtige Hinweise / Best Practice
- String Templates beginnen und enden mit
|(Pipe-Zeichen). - Ausdrücke in
{...}werden zur Laufzeit ausgewertet. - Escape-Sequenzen:
\|für Pipe,\{\}für Klammern,\nfür Zeilenumbruch. - Formatierungsoptionen machen
WRITE TOund Konvertierungsroutinen oft überflüssig. ALPHA = OUTist praktisch für Materialnummern ohne führende Nullen.DATE = ISOliefert standardisiertes Format (YYYY-MM-DD).- Kombinieren Sie mit
CONDundSWITCHfür bedingte Texte. - String Templates sind performant – bevorzugen Sie sie gegenüber
CONCATENATE. - Vorsicht bei dynamischem SQL – verwenden Sie Parameter statt String-Interpolation.
NUMBER = USERrespektiert die Benutzereinstellungen für Dezimal-/Tausendertrennzeichen.