Oracle
 sql >> Base de données >  >> RDS >> Oracle

Comment échapper à un regexp_replace dans Oracle ?

Cela devrait fonctionner à condition que vous n'ayez pas une entrée qui ressemble à %ABC#%ABC#

SELECT REGEXP_REPLACE( '%ABC#abc\%ABC#', '((^|[^\])(\\\\)*)%ABC#', '\1XXX' )
FROM DUAL;

Cela correspondra soit :

  • Le début de la chaîne ^ ou un caractère non-slash [^\] suivi d'un nombre quelconque de paires de barres obliques puis, enfin, des caractères %ABC# . Cela correspondra à %ABC# , \\%ABC# , \\\\%ABC# et ainsi de suite mais ne correspondra pas à \%ABC# , \\\%ABC# , \\\\\%ABC# où il y a une barre oblique échappant au % caractère.

Le remplacement inclut le premier groupe de capture car l'expression peut correspondre à un caractère non-slash précédent et à des paires de barres obliques et ceux-ci doivent être conservés dans la sortie.

Mettre à jour

Cela devient un peu compliqué mais cela fera des correspondances répétées :

WITH Data ( VALUE ) AS (
  SELECT '%ABC#%ABC#' FROM DUAL
)
SELECT ( SELECT LISTAGG(
                  REGEXP_REPLACE( COLUMN_VALUE, '((^|[^\])(\\\\)*)%ABC#$', '\1XXX' ),
                  NULL
                ) WITHIN GROUP ( ORDER BY NULL )
         FROM   TABLE(
                  CAST(
                    MULTISET(
                      SELECT  REGEXP_SUBSTR( d.value, '.*?(%ABC#|$)', 1, LEVEL )
                      FROM    DUAL
                      CONNECT BY LEVEL < REGEXP_COUNT( d.value, '.*?(%ABC#|$)' )
                    AS SYS.ODCIVARCHAR2LIST
                  )
                )
       ) AS Value
FROM   Data d;

Il utilise une sous-requête corrélée pour diviser la chaîne en sous-chaînes qui se terminent par %ABC# ou la fin de chaîne (c'est le bit à l'intérieur du TABLE( CAST( MULTISET( ) .. ) ) ) puis reconcatène ces sous-chaînes après avoir effectué le remplacement à la fin de chaque sous-chaîne.