Las Regular Expressions (Regex) permiten busqueda y reemplazo de patrones complejos en strings. ABAP soporta expresiones regulares compatibles con POSIX a traves de sentencias y clases.
Posibilidades de Uso
FIND … REGEX - Buscar patron en string
REPLACE … REGEX - Reemplazar patron
matches() - Verificar si string corresponde al patron
cl_abap_regex / cl_abap_matcher - API orientada a objetos
Resumen de Sintaxis Regex
Caracter Significado Ejemplo .Cualquier caracter a.c -> abc, aXc*0 o mas ab*c -> ac, abc, abbc+1 o mas ab+c -> abc, abbc?0 o 1 ab?c -> ac, abc^Inicio ^Hello$Fin World$[abc]Clase de caracteres [aeiou] -> Vocales[^abc]Clase negada [^0-9] -> No-digitos[a-z]Rango [A-Za-z] -> Letras\dDigito [0-9] \d{4} -> 4 digitos\wCaracter de palabra [a-zA-Z0-9_] \w+\sEspacio en blanco \s+ -> Espacios\bLimite de palabra \bword\b{n}Exactamente n veces a{3} -> aaa{n,m}n a m veces a{2,4} -> aa, aaa, aaaa(...)Grupo (ab)+ -> ab, abab|O cat|dog
Ejemplos
1. FIND con REGEX
DATA : lv_text TYPE string VALUE 'Pedido 12345 del 2024-11-15' .
FIND REGEX '\d+' IN lv_text MATCH OFFSET DATA (lv_offset)
MATCH LENGTH DATA (lv_length).
DATA (lv_number) = substring ( val = lv_text off = lv_offset len = lv_length ).
WRITE : / 'Encontrado:' , lv_number. " 12345
2. Encontrar Todas las Coincidencias (FIND ALL OCCURRENCES)
DATA : lv_text TYPE string VALUE 'Tel: 030-12345, Fax: 040-67890, Movil: 0170-9876543' .
" Encontrar todos los numeros de telefono
FIND ALL OCCURRENCES OF REGEX '\d{3,4}-\d+'
RESULTS DATA (lt_results).
LOOP AT lt_results INTO DATA (ls_result).
DATA (lv_phone) = substring ( val = lv_text
len = ls_result-length ).
WRITE : / 'Telefono:' , lv_phone.
DATA : lv_date TYPE string VALUE 'Fecha: 2024-11-15' .
" Extraer fecha con grupos
FIND REGEX '(\d{4})-(\d{2})-(\d{2})'
SUBMATCHES DATA (lv_year) DATA (lv_month) DATA (lv_day).
WRITE : / 'Ano:' , lv_year. " 2024
WRITE : / 'Mes:' , lv_month. " 11
WRITE : / 'Dia:' , lv_day. " 15
4. REPLACE con REGEX
DATA : lv_text TYPE string VALUE 'Precio: 123.45 EUR, Descuento: 10.00 EUR' .
" Reemplazar numeros con XXX
REPLACE ALL OCCURRENCES OF REGEX '\d+\.?\d*'
WRITE : / lv_text. " Precio: XXX EUR, Descuento: XXX EUR
5. Referencias Hacia Atras
DATA : lv_text TYPE string VALUE 'El el gato esta sobre sobre el tejado.' .
" Eliminar palabras duplicadas (referencia hacia atras \1)
REPLACE ALL OCCURRENCES OF REGEX '\b(\w+)\s+\1\b'
WRITE : / lv_text. " El gato esta sobre el tejado.
6. matches() - Verificar si Pattern Coincide
" Validacion simple de E-Mail
IF matches ( val = lv_email regex = '^\w+@\w+\.\w+$' ).
WRITE : / 'E-Mail valido' .
WRITE : / 'E-Mail invalido' .
" Multiples verificaciones
DATA : lv_phone TYPE string VALUE '+49-170-1234567' .
DATA (lv_valid_phone) = xsdbool (
matches ( val = lv_phone regex = '^\+?\d{2,3}-\d{2,4}-\d{4,}$' )
7. contains() con Regex
DATA : lv_text TYPE string VALUE 'Pedido Nr. 12345 fue enviado' .
IF contains ( val = lv_text regex = '\d+' ).
WRITE : / 'Texto contiene numeros' .
IF contains ( val = lv_text regex = '^Pedido' ).
8. count() con Regex
DATA : lv_text TYPE string VALUE 'a1b2c3d4e5' .
DATA (lv_digit_count) = count ( val = lv_text regex = '\d' ).
WRITE : / 'Cantidad de digitos:' , lv_digit_count. " 5
DATA : lv_sentence TYPE string VALUE 'Esta es una oracion de ejemplo con palabras' .
DATA (lv_word_count) = count ( val = lv_sentence regex = '\b\w+\b' ).
WRITE : / 'Cantidad de palabras:' , lv_word_count. " 8
9. cl_abap_regex - Orientado a Objetos
DATA : lv_text TYPE string VALUE 'Nombre: Max Mustermann, Edad: 30' .
DATA (lo_regex) = cl_abap_regex=>create_pcre( pattern = '(\w+):\s*(\S+)' ).
DATA (lo_matcher) = lo_regex->create_matcher( text = lv_text ).
" Recorrer todas las coincidencias
WHILE lo_matcher->find_next( ).
DATA (lv_full) = lo_matcher->get_match( ).
DATA (lv_key) = lo_matcher->get_submatch( 1 ).
DATA (lv_value) = lo_matcher->get_submatch( 2 ).
WRITE : / 'Match:' , lv_full.
WRITE : / ' Clave:' , lv_key, 'Valor:' , lv_value.
" Clave: Nombre Valor: Max
DATA : lv_text TYPE string VALUE
DATA : lt_emails TYPE string_table.
" Encontrar todos los E-Mails
FIND ALL OCCURRENCES OF REGEX '[\w.+-]+@[\w.-]+\.\w{2,}'
RESULTS DATA (lt_results).
LOOP AT lt_results INTO DATA (ls_result).
APPEND substring ( val = lv_text
len = ls_result-length ) TO lt_emails.
LOOP AT lt_emails INTO DATA (lv_email).
11. Practico: Limpiar Datos
" Normalizar numero de telefono
DATA : lv_phone TYPE string VALUE '+49 (0) 170 / 123 45 67' .
" Eliminar todos los no-digitos excepto +
REPLACE ALL OCCURRENCES OF REGEX '[^\d+]' IN lv_phone WITH '' .
WRITE : / lv_phone. " +491701234567
" Reducir multiples espacios
DATA : lv_text TYPE string VALUE 'Demasiados espacios aqui' .
REPLACE ALL OCCURRENCES OF REGEX '\s{2,}' IN lv_text WITH ' ' .
WRITE : / lv_text. " Demasiados espacios aqui
12. Practico: Validaciones
" Validar IBAN (simplificado)
DATA : lv_iban TYPE string VALUE 'DE89370400440532013000' .
IF matches ( val = lv_iban regex = '^[A-Z]{2}\d{2}[A-Z0-9]{4}\d{7}([A-Z0-9]?){0,16}$' ).
WRITE : / 'Formato IBAN valido' .
" Validar codigo postal (Espana)
DATA : lv_cp TYPE string VALUE '28001' .
IF matches ( val = lv_cp regex = '^\d{5}$' ).
WRITE : / 'Codigo postal espanol valido' .
" Validar fecha (YYYY-MM-DD)
DATA : lv_date TYPE string VALUE '2024-11-15' .
IF matches ( val = lv_date regex = '^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$' ).
WRITE : / 'Formato de fecha valido' .
13. Practico: Parsing
DATA : lv_log TYPE string VALUE '2024-11-15 10:30:45 [ERROR] Database connection failed' .
FIND REGEX '^(\d{4}-\d{2}-\d{2})\s+(\d{2}:\d{2}:\d{2})\s+\[(\w+)\]\s+(.+)$'
SUBMATCHES DATA (lv_date) DATA (lv_time) DATA (lv_level) DATA (lv_message).
WRITE : / 'Fecha:' , lv_date.
WRITE : / 'Hora:' , lv_time.
WRITE : / 'Nivel:' , lv_level.
WRITE : / 'Mensaje:' , lv_message.
14. Practico: Parsing CSV
DATA : lv_csv TYPE string VALUE 'Max;Mustermann;30;Berlin' .
DATA : lt_fields TYPE string_table.
" Split por punto y coma (alternativa a SPLIT)
FIND ALL OCCURRENCES OF REGEX '[^;]+' IN lv_csv RESULTS DATA (lt_matches).
LOOP AT lt_matches INTO DATA (ls_match).
APPEND substring ( val = lv_csv off = ls_match-offset len = ls_match-length )
" O mas simple con SPLIT:
SPLIT lv_csv AT ';' INTO TABLE lt_fields.
15. Busqueda Case-Insensitive
DATA : lv_text TYPE string VALUE 'ABAP es genial, abap es fantastico' .
" Case-insensitive con (?i)
FIND ALL OCCURRENCES OF REGEX '(?i)abap'
MATCH COUNT DATA (lv_count).
WRITE : / 'Encontrado:' , lv_count, 'veces' . " 2
16. Funcion Escape
DATA : lv_search TYPE string VALUE 'a.b*c?' .
" Escapar caracteres especiales para busqueda literal
DATA (lv_escaped) = escape ( val = lv_search format = cl_abap_format=>e_regex ).
WRITE : / 'Escaped:' , lv_escaped. " a\.b\*c\?
" Ahora lv_escaped puede usarse en REGEX
DATA : lv_text TYPE string VALUE 'Test a.b*c? Final' .
FIND REGEX lv_escaped IN lv_text.
Patrones Regex Comunes
Proposito Pattern Numero \d+ o [0-9]+Numero decimal \d+\.?\d*Palabra \w+ o [A-Za-z]+E-Mail (simple) [\w.+-]+@[\w.-]+\.\w{2,}URL https?://[\w./%-]+Fecha (YYYY-MM-DD) \d{4}-\d{2}-\d{2}CP (ES) \d{5}Telefono (ES) (\+34|0)\d{2,4}[-/]?\d+Direccion IP \d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}Eliminar espacios \s+ -> “Tags HTML <[^>]+>
Opciones FIND/REPLACE
FIND REGEX pattern IN text
[ IGNORING CASE ] " Ignorar mayusculas/minusculas
[ MATCH OFFSET off ] " Posicion inicial de la coincidencia
[ MATCH LENGTH len ] " Longitud de la coincidencia
[ MATCH COUNT cnt ] " Cantidad de coincidencias
[ SUBMATCHES s1 s2 ... ] " Contenidos de grupos
[ RESULTS result_tab ]. " Todas las coincidencias como tabla
Notas Importantes / Mejores Practicas
Sintaxis PCRE (compatible con Perl) con cl_abap_regex=>create_pcre().
Regex ABAP estandar es compatible con POSIX .
Usar escape() para escapar caracteres especiales.
Submatches con (...) para extraccion de grupos.
(?i) al inicio para busqueda case-insensitive .
Performance : Regex compilado (cl_abap_regex) para uso multiple.
matches() verifica si el string completo corresponde al patron.
contains( ... regex = ...) verifica si el patron esta contenido .
\d, \w, \s son formas cortas para clases de caracteres.
Pruebe Regex con herramientas online (regex101.com) antes de la implementacion.