La sentencia FIND busca patrones o subcadenas dentro de strings y tablas. Soporta busquedas simples, expresiones regulares y proporciona informacion detallada sobre las coincidencias encontradas.
Sintaxis
FIND [ FIRST OCCURRENCE OF | ALL OCCURRENCES OF ] { <subcadena> | REGEX <patron> } IN [ TABLE ] <fuente> [ MATCH OFFSET <offset> ] [ MATCH LENGTH <longitud> ] [ MATCH COUNT <conteo> ] [ RESULTS <resultados> ] [ SUBMATCHES <subcoincidencias> ] [ IGNORING CASE | RESPECTING CASE ].Campos del sistema
Despues de FIND:
sy-subrc:0: Coincidencia encontrada4: No se encontraron coincidencias
Ejemplos
1. Busqueda simple de subcadena
DATA: lv_text TYPE string VALUE 'ABAP es un lenguaje de programacion', lv_offset TYPE i, lv_length TYPE i.
FIND 'lenguaje' IN lv_text MATCH OFFSET lv_offset MATCH LENGTH lv_length.
IF sy-subrc = 0. WRITE: / 'Encontrado en posicion:', lv_offset, / 'Longitud:', lv_length.ENDIF.2. Busqueda ignorando mayusculas/minusculas
DATA: lv_text TYPE string VALUE 'El sistema SAP es potente'.
" Por defecto es RESPECTING CASEFIND 'sap' IN lv_text.WRITE: / 'Con case:', sy-subrc. " 4 (no encontrado)
" Ignorar mayusculas/minusculasFIND 'sap' IN lv_text IGNORING CASE.WRITE: / 'Sin case:', sy-subrc. " 0 (encontrado)3. Contar todas las ocurrencias
DATA: lv_text TYPE string VALUE 'uno, dos, uno, tres, uno', lv_count TYPE i.
FIND ALL OCCURRENCES OF 'uno' IN lv_text MATCH COUNT lv_count.
WRITE: / 'Ocurrencias de "uno":', lv_count. " 34. Obtener todas las posiciones (RESULTS)
DATA: lv_text TYPE string VALUE 'ABC 123 XYZ 456 ABC', lt_results TYPE match_result_tab.
FIND ALL OCCURRENCES OF 'ABC' IN lv_text RESULTS lt_results.
LOOP AT lt_results INTO DATA(ls_result). WRITE: / 'Posicion:', ls_result-offset, 'Longitud:', ls_result-length.ENDLOOP.5. Expresiones regulares (REGEX)
" Buscar patron de email simpleFIND REGEX '[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}' IN lv_text MATCH OFFSET DATA(lv_off) MATCH LENGTH DATA(lv_len).
IF sy-subrc = 0. DATA(lv_email) = substring( val = lv_text off = lv_off len = lv_len ). WRITE: / 'Primer email:', lv_email.ENDIF.6. REGEX con todas las coincidencias
DATA: lv_text TYPE string VALUE 'Numeros: 123, 456, 789', lt_matches TYPE match_result_tab.
" Buscar todos los numerosFIND ALL OCCURRENCES OF REGEX '\d+' IN lv_text RESULTS lt_matches.
LOOP AT lt_matches INTO DATA(ls_match). DATA(lv_number) = substring( val = lv_text off = ls_match-offset len = ls_match-length ). WRITE: / 'Numero encontrado:', lv_number.ENDLOOP.7. SUBMATCHES (grupos de captura)
DATA: lv_text TYPE string VALUE 'Fecha: 2024-03-15', lv_year TYPE string, lv_month TYPE string, lv_day TYPE string.
" Patron con grupos de captura ()FIND REGEX '(\d{4})-(\d{2})-(\d{2})' IN lv_text SUBMATCHES lv_year lv_month lv_day.
IF sy-subrc = 0. WRITE: / 'Ano:', lv_year, / 'Mes:', lv_month, / 'Dia:', lv_day.ENDIF.8. SUBMATCHES con tabla de resultados
DATA: lv_text TYPE string VALUE 'Juan Garcia, Ana Lopez, Pedro Martinez', lt_results TYPE match_result_tab.
FIND ALL OCCURRENCES OF REGEX '(\w+)\s+(\w+)' IN lv_text RESULTS lt_results.
LOOP AT lt_results INTO DATA(ls_result). WRITE: / 'Nombre completo encontrado en:', ls_result-offset.
" Acceder a submatches LOOP AT ls_result-submatches INTO DATA(ls_sub). DATA(lv_part) = substring( val = lv_text off = ls_sub-offset len = ls_sub-length ). WRITE: / ' Parte:', lv_part. ENDLOOP.ENDLOOP.9. FIND en tabla interna
DATA: lt_lines TYPE TABLE OF string, lt_results TYPE match_result_tab.
lt_lines = VALUE #( ( `Primera linea de texto` ) ( `Segunda linea con palabra clave` ) ( `Tercera linea normal` ) ( `Cuarta linea con palabra clave de nuevo` )).
" Buscar en toda la tablaFIND ALL OCCURRENCES OF 'palabra clave' IN TABLE lt_lines RESULTS lt_results.
LOOP AT lt_results INTO DATA(ls_result). WRITE: / 'Linea:', ls_result-line, 'Posicion:', ls_result-offset.ENDLOOP.10. FIND en tabla con REGEX
DATA: lt_emails TYPE TABLE OF string, lt_results TYPE match_result_tab.
lt_emails = VALUE #( ( `Sin email aqui` )).
FIND ALL OCCURRENCES OF REGEX '[a-z]+@[a-z]+\.com' IN TABLE lt_emails RESULTS lt_results IGNORING CASE.
LOOP AT lt_results INTO DATA(ls_res). DATA(lv_email) = substring( val = lt_emails[ ls_res-line ] off = ls_res-offset len = ls_res-length ). WRITE: / 'Email en linea', ls_res-line, ':', lv_email.ENDLOOP.11. Verificar existencia (sin detalles)
DATA: lv_text TYPE string VALUE 'Error: operacion fallida'.
" Solo verificar si existeIF find( val = lv_text sub = 'Error' ) >= 0. WRITE: / 'Se encontro mensaje de error'.ENDIF.
" Alternativa con sentencia FINDFIND 'Error' IN lv_text.IF sy-subrc = 0. WRITE: / 'Es un mensaje de error'.ENDIF.12. Patrones REGEX comunes
" Numeros enterosFIND REGEX '^\d+$' IN lv_text.
" Numeros decimalesFIND REGEX '^\d+[.,]\d+$' IN lv_text.
" Direcciones emailFIND REGEX '^[\w.+-]+@[\w.-]+\.\w{2,}$' IN lv_text.
" Numeros de telefono (formato aleman)FIND REGEX '^\+?[\d\s-]{10,}$' IN lv_text.
" Codigo postal alemanFIND REGEX '^\d{5}$' IN lv_text.
" Fechas (YYYY-MM-DD)FIND REGEX '^\d{4}-\d{2}-\d{2}$' IN lv_text.
" Solo letrasFIND REGEX '^[a-zA-Z]+$' IN lv_text.
" AlfanumericoFIND REGEX '^[a-zA-Z0-9]+$' IN lv_text.13. Reemplazar con FIND (obtener posiciones)
DATA: lv_text TYPE string VALUE 'Hola mundo, hola ABAP', lt_results TYPE match_result_tab, lv_new TYPE string.
FIND ALL OCCURRENCES OF 'hola' IN lv_text RESULTS lt_results IGNORING CASE.
" Reemplazar de atras hacia adelante (para no alterar offsets)lv_new = lv_text.LOOP AT lt_results INTO DATA(ls_res). lv_new = substring( val = lv_new off = 0 len = ls_res-offset ) && 'Saludos' && substring( val = lv_new off = ls_res-offset + ls_res-length ).ENDLOOP.
WRITE: / lv_new.14. PCRE vs POSIX Regex
" ABAP usa POSIX-style regex por defecto" Algunas diferencias con PCRE:
" Clases de caracteres" \d -> [0-9]" \w -> [a-zA-Z0-9_]" \s -> espacio, tab, newline
" Cuantificadores" + -> uno o mas" * -> cero o mas" ? -> cero o uno" {n} -> exactamente n" {n,} -> n o mas" {n,m} -> entre n y m
" Anclas" ^ -> inicio de cadena/linea" $ -> fin de cadena/linea
" Grupos" () -> grupo de captura" | -> alternativa (OR)15. Performance: FIND vs alternativas
" Para busquedas simples, usar funciones builtin puede ser mas rapido
" Funcion find() - retorna posicion (-1 si no encontrado)DATA(lv_pos) = find( val = lv_text sub = 'buscar' ).
" Funcion count() - cuenta ocurrenciasDATA(lv_cnt) = count( val = lv_text sub = 'buscar' ).
" Funcion contains() - retorna booleanoIF contains( val = lv_text sub = 'buscar' ). " ...ENDIF.
" Operador CS (Contains String)IF lv_text CS 'buscar'. " Mas simple pero menos flexibleENDIF.Estructura match_result
" Componentes de match_result:" - OFFSET: Posicion del inicio de la coincidencia" - LENGTH: Longitud de la coincidencia" - LINE: Numero de linea (para busquedas en tablas)" - SUBMATCHES: Tabla de subcoincidencias (grupos de captura)Resumen
| Variante | Descripcion |
|---|---|
FIRST OCCURRENCE OF | Solo primera coincidencia (por defecto) |
ALL OCCURRENCES OF | Todas las coincidencias |
REGEX | Usar expresion regular |
IGNORING CASE | Ignorar mayusculas/minusculas |
IN TABLE | Buscar en tabla interna |
RESULTS | Obtener detalles de todas las coincidencias |
SUBMATCHES | Obtener grupos de captura |
Notas importantes / Mejores practicas
- Verificar sy-subrc para saber si hubo coincidencias.
- Usar
IGNORING CASEpara busquedas insensibles a mayusculas. ALL OCCURRENCESconRESULTSpara procesar multiples coincidencias.- REGEX para patrones complejos pero es mas lento.
SUBMATCHESextrae grupos de captura()de regex.- Para busquedas simples, las funciones find() y contains() son mas concisas.
- En tablas,
ls_result-lineindica el numero de fila. - Escapar caracteres especiales en regex con
\.