Ir para o conteúdo

Expressões

String Templates

Sintaxe Básica

DATA(lv_nome) = 'João Silva'.
DATA(lv_idade) = 30.

" Template simples
DATA(lv_msg) = |Olá, { lv_nome }!|.

" Múltiplas variáveis
DATA(lv_info) = |Nome: { lv_nome }, Idade: { lv_idade } anos|.

" Com expressões
DATA(lv_calc) = |O dobro da idade é { lv_idade * 2 }|.

Formatação em Templates

DATA(lv_valor) = '1234.567'.
DATA(lv_data) = sy-datum.

" Números com formatação
DATA(lv_fmt1) = |Valor: { lv_valor NUMBER = USER }|.  " Formato utilizador
DATA(lv_fmt2) = |Preço: { lv_valor CURRENCY = 'EUR' }|.

" Datas
DATA(lv_data_fmt) = |Data: { lv_data DATE = USER }|.
DATA(lv_data_iso) = |Data ISO: { lv_data DATE = ISO }|.

" Alinhamento (ALIGN LEFT/CENTER/RIGHT)
DATA(lv_align) = |{ 'Texto' WIDTH = 20 ALIGN = RIGHT }|.
DATA(lv_pad) = |{ lv_idade WIDTH = 5 ALIGN = RIGHT PAD = '0' }|.  " 00030

" Maiúsculas/Minúsculas
DATA(lv_upper) = |{ lv_nome CASE = UPPER }|.  " JOÃO SILVA
DATA(lv_lower) = |{ lv_nome CASE = LOWER }|.  " joão silva

Templates Complexos

" Com condições inline
DATA(lv_status) = |Cliente { COND #( WHEN lv_ativo = abap_true 
                                      THEN 'ativo' 
                                      ELSE 'inativo' ) }|.

" Aninhado
DATA(lv_relatorio) = |Resumo: { |Total: { lv_total }| }|.

" Com chamada de método
DATA(lv_result) = |Resultado: { lo_objeto->get_valor( ) }|.

" Multilinha (com \n ou caracteres especiais)
DATA(lv_email) = |Olá { lv_nome },{ cl_abap_char_utilities=>newline }|
              && |{ cl_abap_char_utilities=>newline }|
              && |Obrigado pela sua encomenda.|.

Operadores Aritméticos

Operações Básicas

DATA(lv_a) = 10.
DATA(lv_b) = 3.

" Adição, subtração, multiplicação, divisão
DATA(lv_soma) = lv_a + lv_b.      " 13
DATA(lv_sub) = lv_a - lv_b.       " 7
DATA(lv_mult) = lv_a * lv_b.      " 30
DATA(lv_div) = lv_a / lv_b.       " 3 (divisão inteira)

" Divisão com decimais
DATA(lv_div_dec) = CONV decfloat34( lv_a ) / lv_b.  " 3.333...

" Módulo (resto da divisão)
DATA(lv_resto) = lv_a MOD lv_b.   " 1

" Potência
DATA(lv_pot) = lv_a ** 2.         " 100

" Operações combinadas
DATA(lv_result) = ( lv_a + lv_b ) * 2 - 5.

Operações com Atribuição

DATA lv_contador TYPE i VALUE 10.

" Incremento e decremento
lv_contador = lv_contador + 1.
lv_contador = lv_contador - 1.

" Multiplicação/divisão com atribuição
lv_contador = lv_contador * 2.
lv_contador = lv_contador / 2.

" ADD, SUBTRACT, MULTIPLY, DIVIDE (forma tradicional)
ADD 5 TO lv_contador.
SUBTRACT 3 FROM lv_contador.
MULTIPLY lv_contador BY 2.
DIVIDE lv_contador BY 4.

Operações com Strings

Concatenação

DATA(lv_primeiro) = 'João'.
DATA(lv_ultimo) = 'Silva'.

" Operador && (mantém espaços)
DATA(lv_nome1) = lv_primeiro && ' ' && lv_ultimo.

" CONCATENATE (remove espaços trailing por defeito)
DATA lv_nome2 TYPE string.
CONCATENATE lv_primeiro lv_ultimo INTO lv_nome2 SEPARATED BY space.

" String template (recomendado)
DATA(lv_nome3) = |{ lv_primeiro } { lv_ultimo }|.

Manipulação de Strings

DATA(lv_texto) = '  ABAP Programming  '.

" Comprimento
DATA(lv_len) = strlen( lv_texto ).

" Remover espaços
DATA(lv_trim) = condense( lv_texto ).  " Remove espaços extra
lv_texto = shift_left( val = lv_texto ).   " Remove espaços à esquerda
lv_texto = shift_right( val = lv_texto ).  " Remove espaços à direita

" Substituir
DATA(lv_novo) = replace( val = lv_texto sub = 'ABAP' with = 'SAP' ).

" Substring
DATA(lv_sub) = substring( val = lv_texto off = 2 len = 4 ).

" Maiúsculas/Minúsculas
DATA(lv_upper) = to_upper( lv_texto ).
DATA(lv_lower) = to_lower( lv_texto ).

" Dividir string
SPLIT lv_texto AT space INTO DATA(lv_part1) DATA(lv_part2).

" Encontrar
DATA(lv_pos) = find( val = lv_texto sub = 'Programming' ).
IF lv_pos >= 0.
  WRITE: / |Encontrado na posição { lv_pos }|.
ENDIF.

Match e Expressões Regulares

DATA(lv_email) = 'utilizador@example.com'.

" Verificar padrão
IF matches( val = lv_email regex = '^\w+@\w+\.\w+$' ).
  WRITE: / 'Email válido'.
ENDIF.

" Extrair com regex
DATA(lv_dominio) = replace( val = lv_email regex = '^.*@' with = '' ).

" Contar ocorrências
DATA(lv_count) = count( val = 'teste teste teste' sub = 'teste' ).

Operações com Tabelas Internas

Leitura de Linhas

" Acesso direto por índice []
DATA(ls_primeiro) = lt_clientes[ 1 ].  " Primeira linha

" Com DEFAULT (evita dump se não existir)
DATA(ls_cliente) = VALUE #( lt_clientes[ id = 100 ] DEFAULT ls_default ).

" Acesso a campo específico
DATA(lv_nome) = lt_clientes[ 1 ]-nome.

" Opcional com ?
TRY.
    DATA(ls_opt) = lt_clientes[ id = 999 ].
  CATCH cx_sy_itab_line_not_found.
    " Linha não encontrada
ENDTRY.

Funções de Tabela

" Número de linhas
DATA(lv_count) = lines( lt_clientes ).

" Existe linha?
IF line_exists( lt_clientes[ id = 100 ] ).
  WRITE: / 'Cliente existe'.
ENDIF.

" Índice da linha
DATA(lv_idx) = line_index( lt_clientes[ nome = 'João' ] ).

FILTER

" Filtrar tabela
DATA(lt_ativos) = FILTER #( lt_clientes WHERE ativo = abap_true ).

" Com múltiplas condições
DATA(lt_filtrado) = FILTER #( lt_produtos 
  WHERE categoria = 'ELETRO' 
    AND preco > 100 
    AND stock > 0 
).

" EXCEPT - excluir registos
DATA(lt_inativos) = FILTER #( lt_clientes EXCEPT WHERE ativo = abap_true ).

VALUE Constructor

Criar Estruturas

" Estrutura simples
DATA(ls_pessoa) = VALUE ty_pessoa(
  id    = 1
  nome  = 'Ana'
  idade = 25
).

" Com BASE (manter valores existentes)
ls_pessoa = VALUE #( BASE ls_pessoa
  idade = 26
).

" Estrutura aninhada
DATA(ls_pedido) = VALUE ty_pedido(
  numero = '001'
  cliente = VALUE #(
    id   = 100
    nome = 'Cliente XYZ'
  )
  itens = VALUE #(
    ( produto = 'A' qtd = 5 )
    ( produto = 'B' qtd = 3 )
  )
).

Criar Tabelas

" Tabela com valores diretos
DATA(lt_numeros) = VALUE ty_t_int( ( 1 ) ( 2 ) ( 3 ) ( 4 ) ( 5 ) ).

" Tabela de estruturas
DATA(lt_clientes) = VALUE ty_t_clientes(
  ( id = 1 nome = 'João'  ativo = abap_true )
  ( id = 2 nome = 'Maria' ativo = abap_true )
  ( id = 3 nome = 'Pedro' ativo = abap_false )
).

" Com BASE (adicionar a existente)
lt_clientes = VALUE #( BASE lt_clientes
  ( id = 4 nome = 'Ana' ativo = abap_true )
).

" Com LINES OF (juntar tabelas)
DATA(lt_todos) = VALUE ty_t_clientes(
  ( id = 1 nome = 'A' )
  LINES OF lt_clientes
  ( id = 999 nome = 'Z' )
).

CORRESPONDING

Entre Estruturas

" Copiar campos com mesmo nome
DATA(ls_destino) = CORRESPONDING ty_destino( ls_origem ).

" Com BASE
ls_destino = CORRESPONDING #( BASE ls_destino ls_origem ).

" Com MAPPING (mapear campos diferentes)
ls_destino = CORRESPONDING #( ls_origem 
  MAPPING campo_dest = campo_orig
          nome_novo  = nome_antigo
).

" EXCEPT (excluir campos)
ls_destino = CORRESPONDING #( ls_origem EXCEPT campo1 campo2 ).

Entre Tabelas

" Converter tabela completa
DATA(lt_destino) = CORRESPONDING ty_t_destino( lt_origem ).

" Manter registos + adicionar
lt_destino = CORRESPONDING #( BASE lt_destino lt_origem ).

" Com transformação inline
DATA(lt_resumo) = CORRESPONDING ty_t_resumo( lt_vendas
  MAPPING id_resumo = id_venda
          valor_total = valor
).

CONV (Conversão de Tipos)

" Converter tipos básicos
DATA(lv_string) = '12345'.
DATA(lv_int) = CONV i( lv_string ).

DATA(lv_decimal) = CONV decfloat34( '3.14159' ).
DATA(lv_packed) = CONV p( lv_decimal ).

" Em expressões
DATA(lv_resultado) = CONV decfloat34( lv_valor1 ) / CONV decfloat34( lv_valor2 ).

" Com data/hora
DATA(lv_timestamp) = CONV timestamp( utclong_current( ) ).

CAST (Conversão de Objetos)

" Cast de referências
DATA lo_generic TYPE REF TO object.
DATA(lo_specific) = CAST cl_my_class( lo_generic ).

" Cast seguro com TRY
TRY.
    DATA(lo_cliente) = CAST cl_cliente( lo_objeto ).
    lo_cliente->processar( ).
  CATCH cx_sy_move_cast_error.
    " Cast falhou
ENDTRY.

" Verificar tipo antes
IF lo_objeto IS INSTANCE OF cl_cliente.
  DATA(lo_cli) = CAST cl_cliente( lo_objeto ).
ENDIF.

REF (Criar Referência)

" Criar referência a variável
DATA lv_valor TYPE i VALUE 100.
DATA(lr_valor) = REF #( lv_valor ).

" Modificar via referência
lr_valor->* = 200.  " lv_valor agora é 200

" Referência a estrutura
DATA ls_cliente TYPE ty_cliente.
DATA(lr_cliente) = REF #( ls_cliente ).
lr_cliente->nome = 'João'.

" Criar nova instância
DATA(lr_nova) = NEW ty_cliente( ).

Dicas de Boas Práticas

String Templates

  • Use sempre string templates em vez de CONCATENATE
  • Mais legível e menos propenso a erros
  • Performance equivalente ou melhor

Cuidado com Conversões

" ❌ Pode perder precisão
DATA(lv_result) = 10 / 3.  " Resultado: 3 (inteiro)

" ✅ Converter para decimal primeiro
DATA(lv_result) = CONV decfloat34( 10 ) / 3.  " 3.333...

" ❌ Acesso direto pode causar dump
DATA(ls_cliente) = lt_clientes[ 999 ].

" ✅ Com tratamento de erro
TRY.
    DATA(ls_cliente) = lt_clientes[ 999 ].
  CATCH cx_sy_itab_line_not_found.
ENDTRY.

Expressões Modernas

" ❌ Forma antiga
DATA lv_resultado TYPE string.
IF lv_idade >= 18.
  lv_resultado = 'Adulto'.
ELSE.
  lv_resultado = 'Menor'.
ENDIF.
CONCATENATE 'Status:' lv_resultado INTO lv_resultado SEPARATED BY space.

" ✅ Forma moderna
DATA(lv_resultado) = |Status: { COND #( WHEN lv_idade >= 18 
                                         THEN 'Adulto' 
                                         ELSE 'Menor' ) }|.

Performance de Expressões

  • VALUE, CORRESPONDING, FILTER são otimizados pelo compilador
  • String templates são tão rápidos quanto CONCATENATE
  • Use inline declarations para reduzir código
  • REDUCE é eficiente para agregações

Tags: #Fundamentos #Expressões #Modern-ABAP #Performance