Los String Templates (tambien llamados Template Strings) permiten la creacion elegante de strings con expresiones embebidas y opciones de formateo. Se delimitan con |...| y contienen expresiones en {...}.
Sintaxis
|Texto literal { expresion } mas texto||{ expresion OPCION = valor }|Principio basico
- El texto entre
|...|se interpreta como string {...}contiene expresiones que se evaluan e insertan- Las opciones de formateo controlan la presentacion
- Secuencias de escape para caracteres especiales:
\|,\{,\},\\,\n,\r,\t
Ejemplos
1. Interpolacion simple
DATA: lv_name TYPE string VALUE 'Max', lv_age TYPE i VALUE 30.
" Clasico con CONCATENATEDATA: lv_text TYPE string.CONCATENATE 'Hola ' lv_name ', tienes ' lv_age ' anos.' INTO lv_text.
" Moderno con String TemplateDATA(lv_text2) = |Hola { lv_name }, tienes { lv_age } anos.|.
WRITE: / lv_text2. " Hola Max, tienes 30 anos.2. Expresiones en templates
DATA: lv_a TYPE i VALUE 10, lv_b TYPE i VALUE 5.
" Calculos directamente embebidosDATA(lv_calc) = |{ lv_a } + { lv_b } = { lv_a + lv_b }|.WRITE: / lv_calc. " 10 + 5 = 15
" Llamadas a metodosDATA(lv_upper) = |Nombre: { to_upper( lv_name ) }|.WRITE: / lv_upper. " Nombre: MAX
" Expresiones condicionalesDATA(lv_status) = |Estado: { COND #( WHEN lv_age >= 18 THEN 'Adulto' ELSE 'Menor' ) }|.3. Formateo de numeros (WIDTH, ALIGN, PAD)
DATA: lv_num TYPE i VALUE 42.
" Ancho minimo con WIDTHDATA(lv_w) = |Numero: { lv_num WIDTH = 10 }|.WRITE: / lv_w. " Numero: 42
" Alineacion con 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 ]
" Caracter de relleno con PADDATA(lv_padded) = |{ lv_num WIDTH = 6 ALIGN = RIGHT PAD = '0' }|.WRITE: / lv_padded. " 0000424. Formatear decimales (DECIMALS, SIGN)
DATA: lv_amount TYPE p DECIMALS 2 VALUE '-1234.56'.
" Especificar decimalesDATA(lv_d1) = |Importe: { lv_amount DECIMALS = 2 }|.WRITE: / lv_d1. " Importe: -1234.56
" Posicion del signoDATA(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 (+ para positivos)
" Separador de milesDATA: lv_big TYPE p DECIMALS 2 VALUE '1234567.89'.DATA(lv_sep) = |{ lv_big NUMBER = USER }|. " Formato usuario (ej. 1.234.567,89)DATA(lv_raw) = |{ lv_big NUMBER = RAW }|. " Sin formateo5. Formateo de fechas (DATE)
DATA: lv_date TYPE d VALUE '20241115'.
" Diferentes formatos de fechaDATA(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 }|. " Formato usuarioDATA(lv_d_env) = |{ lv_date DATE = ENVIRONMENT }|.
WRITE: / 'RAW:', lv_d_raw.WRITE: / 'ISO:', lv_d_iso.WRITE: / 'USER:', lv_d_user.6. Formateo de hora (TIME)
DATA: lv_time TYPE t VALUE '143025'.
" Diferentes formatos de horaDATA(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 }|. " Formato usuario
WRITE: / 'Hora:', lv_t_iso.7. Formatear timestamp (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. Conversion Alpha (ALPHA)
DATA: lv_matnr TYPE string VALUE '000000000000012345'.
" Alpha OUT: Eliminar ceros inicialesDATA(lv_without_zeros) = |{ lv_matnr ALPHA = OUT }|.WRITE: / lv_without_zeros. " 12345
" Alpha IN: Anadir ceros inicialesDATA: lv_short TYPE string VALUE '12345'.DATA(lv_with_zeros) = |{ lv_short ALPHA = IN WIDTH = 18 }|.WRITE: / lv_with_zeros. " 0000000000000123459. Conversion de mayusculas/minusculas (CASE)
DATA: lv_text TYPE string VALUE 'Hola Mundo'.
DATA(lv_upper) = |{ lv_text CASE = UPPER }|. " HOLA MUNDODATA(lv_lower) = |{ lv_text CASE = LOWER }|. " hola mundoDATA(lv_raw) = |{ lv_text CASE = RAW }|. " Hola Mundo
WRITE: / lv_upper.WRITE: / lv_lower.10. Secuencias de escape
" Escapar caracteres especialesDATA(lv_pipe) = |Pipe: \| y llave: \{ \}|.DATA(lv_newline) = |Linea 1\nLinea 2|.DATA(lv_tab) = |Columna1\tColumna2|.DATA(lv_backsl) = |Ruta: C:\\Carpeta\\Archivo|.
WRITE: / lv_pipe.WRITE: / lv_newline.WRITE: / lv_tab.11. String Templates multilinea
" Los strings pueden extenderse en varias lineasDATA(lv_multi) = |Este es un | && |string | && |multilinea.|.
" O con \n para saltos de linea realesDATA(lv_lines) = |Linea 1\n| && |Linea 2\n| && |Linea 3|.
cl_demo_output=>display( lv_lines ).12. Combinacion con COND y SWITCH
DATA: lv_status TYPE i VALUE 2.
DATA(lv_msg) = |Estado: { SWITCH string( lv_status WHEN 1 THEN 'Nuevo' WHEN 2 THEN 'En proceso' WHEN 3 THEN 'Completado' ELSE 'Desconocido') }|.
WRITE: / lv_msg. " Estado: En proceso13. Embeber campos de estructura
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 = 'Garcia S.L.' city = 'Madrid' ).
DATA(lv_info) = |Cliente { ls_customer-id }: { ls_customer-name } de { ls_customer-city }|.
WRITE: / lv_info. " Cliente 1001: Garcia S.L. de Madrid14. Acceso a tablas en templates
DATA: lt_names TYPE TABLE OF string.
lt_names = VALUE #( ( `Ana` ) ( `Berto` ) ( `Clara` ) ).
" Acceso directo a tablaDATA(lv_first) = |Primera entrada: { lt_names[ 1 ] }|.WRITE: / lv_first. " Primera entrada: Ana
" Con OPTIONAL para accesos segurosDATA(lv_safe) = |Entrada: { VALUE #( lt_names[ 999 ] OPTIONAL ) }|.15. String Templates en bucles
LOOP AT lt_names INTO DATA(lv_name). DATA(lv_line) = |{ sy-tabix }. { lv_name }|. WRITE: / lv_line.ENDLOOP.
" Salida:" 1. Ana" 2. Berto" 3. Clara16. String Templates para SQL
" Construir SQL dinamico (Cuidado: SQL Injection!)DATA: lv_field TYPE string VALUE 'CARRID', lv_value TYPE string VALUE 'LH'.
" Mejor: Usar parametros en lugar de concatenacion de strings para SQL17. Combinar opciones de formateo
DATA: lv_price TYPE p DECIMALS 2 VALUE '1234.50'.
DATA(lv_formatted) = |Precio: { lv_price DECIMALS = 2 SIGN = LEFT WIDTH = 12 ALIGN = RIGHT PAD = ' '} EUR|.
WRITE: / lv_formatted. " Precio: 1234.50 EUR18. Formato XSD para Boolean
DATA: lv_flag TYPE abap_bool VALUE abap_true.
" Formato XSD: true/false en lugar de X/''DATA(lv_xsd) = |Activo: { xsdbool( lv_flag ) }|.WRITE: / lv_xsd. " Activo: X
" Representacion personalizadaDATA(lv_custom) = |Activo: { COND #( WHEN lv_flag = abap_true THEN 'Si' ELSE 'No' ) }|.Resumen de opciones de formateo
| Opcion | Valores | Descripcion |
|---|---|---|
WIDTH | Numero | Ancho minimo |
ALIGN | LEFT, RIGHT, CENTER | Alineacion |
PAD | Caracter | Caracter de relleno |
CASE | UPPER, LOWER, RAW | Mayusculas/minusculas |
SIGN | LEFT, RIGHT, LEFTPLUS, RIGHTPLUS | Posicion del signo |
DECIMALS | Numero | Decimales |
NUMBER | RAW, USER, ENVIRONMENT | Formato numerico |
DATE | RAW, ISO, USER, ENVIRONMENT | Formato fecha |
TIME | RAW, ISO, USER, ENVIRONMENT | Formato hora |
TIMESTAMP | ISO, SPACE, USER | Formato timestamp |
ALPHA | IN, OUT, RAW | Conversion Alpha |
CURRENCY | Codigo moneda | Formato moneda |
COUNTRY | Codigo pais | Formato pais |
Comparacion: Clasico vs. String Templates
" === CLASICO ===DATA: lv_result TYPE string.
CONCATENATE 'Cliente' ls_customer-id ':' ls_customer-name INTO lv_result SEPARATED BY space.
" O con &&lv_result = 'Cliente ' && ls_customer-id && ': ' && ls_customer-name.
" === MODERNO CON STRING TEMPLATES ===DATA(lv_result2) = |Cliente { ls_customer-id }: { ls_customer-name }|.Notas importantes / Mejores practicas
- Los String Templates comienzan y terminan con
|(caracter pipe). - Las expresiones en
{...}se evaluan en tiempo de ejecucion. - Secuencias de escape:
\|para pipe,\{\}para llaves,\npara salto de linea. - Las opciones de formateo hacen innecesarios
WRITE TOy rutinas de conversion en muchos casos. ALPHA = OUTes practico para numeros de material sin ceros iniciales.DATE = ISOproporciona formato estandarizado (YYYY-MM-DD).- Combine con
CONDySWITCHpara textos condicionales. - Los String Templates son eficientes - prefieralos sobre
CONCATENATE. - Cuidado con SQL dinamico - use parametros en lugar de interpolacion de strings.
NUMBER = USERrespeta la configuracion del usuario para separadores decimal/miles.