termina regulares regular probar minimo expresiones expresion especiales espacio ejemplos cualquier con caracteres caracter blanco alfanumerico regex oracle oracle11g oracle10g regex-greedy

regex - probar - expresiones regulares java



¿Por qué el cuantificador no codicioso a veces no funciona en expresiones regulares de Oracle? (5)

¡Es un ERROR!

Tiene razón en que en Perl, ''A=1,B=2,C=3,'' =~ /.*B=.*?,/; print $& ''A=1,B=2,C=3,'' =~ /.*B=.*?,/; print $& imprime A=1,B=2,

Lo que ha encontrado es un error que todavía existe en Oracle Database 11g R2. Si el mismo operador de expresión regular (excluyendo el modificador de codicia) aparece dos veces en una expresión regular, ambas apariciones tendrán la codicia indicada por la primera aparición, independientemente de la codicia especificada por la segunda. Que este es un error queda claramente demostrado por estos resultados:

SQL> SELECT regexp_substr(''A=1,B=2,C=3,'', ''[^B]*B=[^Bx]*?,'') as good FROM dual; GOOD -------- A=1,B=2, SQL> SELECT regexp_substr(''A=1,B=2,C=3,'', ''[^B]*B=[^B]*?,'') as bad FROM dual; BAD ----------- A=1,B=2,C=3,

La única diferencia entre las dos expresiones regulares es que la "buena" excluye ''x'' como posible coincidencia en la segunda lista coincidente. Como ''x'' no aparece en la cadena de destino, excluirla no debería hacer ninguna diferencia, pero como puede ver, eliminar la ''x'' hace una gran diferencia. Eso tiene que ser un error.

Aquí hay algunos ejemplos más de Oracle 11.2: ( Fiddle de SQL con aún más ejemplos )

SELECT regexp_substr(''A=1,B=2,C=3,'', ''.*B=.*?,'') FROM dual; => A=1,B=2,C=3, SELECT regexp_substr(''A=1,B=2,C=3,'', ''.*B=.*,'') FROM dual; => A=1,B=2,C=3, SELECT regexp_substr(''A=1,B=2,C=3,'', ''.*?B=.*?,'') FROM dual; => A=1,B=2, SELECT regexp_substr(''A=1,B=2,C=3,'', ''.*?B=.*,'') FROM dual; => A=1,B=2, -- Changing second operator from * to + SELECT regexp_substr(''A=1,B=2,C=3,'', ''.*B=.+?,'') FROM dual; => A=1,B=2, SELECT regexp_substr(''A=1,B=2,C=3,'', ''.*B=.+,'') FROM dual; => A=1,B=2,C=3, SELECT regexp_substr(''A=1,B=2,C=3,'', ''.+B=.+,'') FROM dual; => A=1,B=2,C=3, SELECT regexp_substr(''A=1,B=2,C=3,'', ''.+?B=.+,'') FROM dual; => A=1,B=2,

El patrón es consistente: la codicia de la primera ocurrencia se usa para la segunda ocurrencia ya sea que deba ser o no.

OMI, esta consulta debe devolver A=1,B=2,

SELECT regexp_substr(''A=1,B=2,C=3,'', ''.*B=.*?,'') as A_and_B FROM dual

Pero devuelve toda la cadena A=1,B=2,C=3, lugar. ¿Por qué?

UPD: Se requiere Oracle 10.2+ para usar metacaracteres de estilo Perl en expresiones regulares.

UPD2:
Una forma más clara de mi pregunta (para evitar preguntas sobre la versión de Oracle y la disponibilidad de la extensión de expresiones regulares de estilo Perl):
¿Por qué en el mismo sistema el cuantificador no codicioso a veces funciona como se espera y otras no?

Esto funciona correctamente:

regexp_substr(''A=1,B=2,C=3,'', ''B=.*?,'')

Esto no funciona:

regexp_substr(''A=1,B=2,C=3,'', ''.*B=.*?,'')

fiddle

UPD3:
Sí, parece ser un error.
¿Alguien puede proporcionar una reacción de soporte de Oracle en este problema?
¿Ya se conoce el error?
¿Tiene una identificación?


En cuanto a los comentarios, vacilo en saltar, pero aquí voy ;-)

De acuerdo con los documentos de Oracle , el *? y +? coincide con una "subexpresión precedente". Por *? específicamente:

Coincide con cero o más apariciones de la subexpresión anterior (nongreedyFootref 1). Coincide con la cadena vacía siempre que sea posible.

Para crear un grupo de subexpresión, use paréntesis ():

Trata la expresión entre paréntesis como una unidad. La expresión puede ser una cadena o una expresión compleja que contiene operadores.

Puede referirse a una subexpresión en una referencia posterior.

Esto le permitirá utilizar codiciosos y no codiciosos (en realidad muchos tiempos alternativos) en la misma expresión regular, con los resultados esperados. Para su ejemplo:

select regexp_substr(''A=1,B=2,C=3,'', ''(.)*B=(.)*?,'') from dual;

Para hacer el punto un poco más claro (espero), este ejemplo utiliza codiciosos y no codiciosos en el mismo regexp_substr, con diferentes resultados (correctos) dependiendo de dónde? se coloca ( NO solo usa la regla para la primera subexpresión que ve ). También tenga en cuenta que la subexpresión (/ w) coincidirá solo con caracteres alfanuméricos y de subrayado, no con @.

-- non-greedy followed by greedy select regexp_substr(''1_@_2_a_3_@_4_a'', ''(/w)*?@(/w)*'') from dual;

resultado: 1 _ @ _ 2_a_3_

-- greedy followed by non-greedy select regexp_substr(''1_@_2_a_3_@_4_a'', ''(/w)*@(/w)*?'') from dual;

resultado: 1_ @


Mi guion:

SET SERVEROUTPUT ON <<DISCREET_DROP>> begin DBMS_OUTPUT.ENABLE; for dropit in (select ''DROP TABLE '' || TABLE_NAME || '' CASCADE CONSTRAINTS'' AS SYNT FROM TABS WHERE TABLE_NAME IN (''TEST_PATS'', ''TEST_STRINGS'') ) LOOP DBMS_OUTPUT.PUT_LINE(''Dropping via '' || dropit.synt); execute immediate dropit.synt; END LOOP; END DISCREET_DROP; / -------------------------------------------------------- -- DDL for Table TEST_PATS -------------------------------------------------------- CREATE TABLE TEST_PATS ( RE VARCHAR2(2000), FROM_WHOM VARCHAR2(50), PAT_GROUP VARCHAR2(50), PAT_ORDER NUMBER(9,0) ) ; / -------------------------------------------------------- -- DDL for Table TEST_STRINGS -------------------------------------------------------- CREATE TABLE TEST_STRINGS ( TEXT VARCHAR2(2000), SRC VARCHAR2(200), TEXT_GROUP VARCHAR2(50), TEXT_ORDER NUMBER(9,0) ) ; / -------------------------------------------------------- -- DDL for View REGEXP_TESTER_V -------------------------------------------------------- CREATE OR REPLACE FORCE VIEW REGEXP_TESTER_V (CASE_NUMBER, SRC, TEXT, RE, FROM_WHOM, RESULT) AS select pat_order as case_number, src, text, re, from_whom, regexp_substr (text, re) as result from test_pats full outer join test_strings on (text_group = pat_group) order by pat_order, text_order; / REM INSERTING into TEST_PATS SET DEFINE OFF; Insert into TEST_PATS (RE,FROM_WHOM,PAT_GROUP,PAT_ORDER) values (''.*B=.*?,'',''Egor''''s original pattern "doesn''''t work"'',''Egor'',1); Insert into TEST_PATS (RE,FROM_WHOM,PAT_GROUP,PAT_ORDER) values (''.*B=.?,'',''Egor''''s "works correctly"'',''Egor'',2); Insert into TEST_PATS (RE,FROM_WHOM,PAT_GROUP,PAT_ORDER) values (''.*B=(.)*?,'',''Schemaczar Variant to force Perl operation'',''Egor'',30); Insert into TEST_PATS (RE,FROM_WHOM,PAT_GROUP,PAT_ORDER) values (''.*B=(.*)?,'',''Schemaczar Variant of Egor to force POSIX'',''Egor'',31); Insert into TEST_PATS (RE,FROM_WHOM,PAT_GROUP,PAT_ORDER) values (''.*B=.*{0,1}'',''Schemaczar Applying Egor''''s ''''non-greedy'''''',''Egor'',32); Insert into TEST_PATS (RE,FROM_WHOM,PAT_GROUP,PAT_ORDER) values (''.*B=(.)*{0,1}'',''Schemaczar Another variant of Egor''''s "non-greedy"'',''Egor'',33); Insert into TEST_PATS (RE,FROM_WHOM,PAT_GROUP,PAT_ORDER) values (''[^B]*B=[^Bx]*?,'',''Old Pro answer form 1 "good"'',''Egor'',6); Insert into TEST_PATS (RE,FROM_WHOM,PAT_GROUP,PAT_ORDER) values (''[^B]*B=[^B]*?,'',''Old Pro answer form 2 "bad"'',''Egor'',7); Insert into TEST_PATS (RE,FROM_WHOM,PAT_GROUP,PAT_ORDER) values (''.*B=.+?,'',''Old Pro comment 1 form 2'',''Egor'',3); Insert into TEST_PATS (RE,FROM_WHOM,PAT_GROUP,PAT_ORDER) values (''.*B=.{0,}?,'',''Old Pro comment 2'',''Egor'',5); Insert into TEST_PATS (RE,FROM_WHOM,PAT_GROUP,PAT_ORDER) values (''.+B=.*?,'',''Old Pro comment 1 form 1'',''Egor'',4); Insert into TEST_PATS (RE,FROM_WHOM,PAT_GROUP,PAT_ORDER) values (''(.)*B=(.)*?,'',''TBone answer form 1'',''Egor'',8); Insert into TEST_PATS (RE,FROM_WHOM,PAT_GROUP,PAT_ORDER) values (''(/w)*?@(/w)*'',''TBone answer example 2 form 1'',''TBone'',9); Insert into TEST_PATS (RE,FROM_WHOM,PAT_GROUP,PAT_ORDER) values (''(/w)*@(/w)*?'',''TBone answer example 2 form 2'',''TBone'',10); REM INSERTING into TEST_STRINGS SET DEFINE OFF; Insert into TEST_STRINGS (TEXT,SRC,TEXT_GROUP,TEXT_ORDER) values (''A=1,B=2,C=3,'',''Egor''''s original source string'',''Egor'',1); Insert into TEST_STRINGS (TEXT,SRC,TEXT_GROUP,TEXT_ORDER) values (''1_@_2_a_3_@_4_a'',''TBone answer example 2'',''TBone'',2); COLUMN SRC FORMAT A50 WORD_WRAP COLUMN TEXT FORMAT A50 WORD_WRAP COLUMN RE FORMAT A50 WORD_WRAP COLUMN FROM_WHOM FORMAT A50 WORD_WRAP COLUMN RESULT FORMAT A50 WORD_WRAP SELECT * FROM REGEXP_TESTER_V;


Tienes una gran recompensa, así que voy a tratar de concretarla.

Usted hace suposiciones en su manejo de expresiones regulares que son incorrectas.

  1. Oracle NO es compatible con expresiones regulares de Perl, es compatible con POSIX. Describe su soporte para Perl como "influenciado por Perl".
  2. Existe un conflicto de sintaxis intrínseca en torno al uso del Perl "*?" en Oracle, si lees esa referencia como lo hago, y Oracle elige legítimamente el uso de POSIX
  3. Su descripción de cómo Perl maneja "*?" No está del todo bien.

Aquí hay un mashup de las opciones que hemos discutido. La clave de este problema es alrededor del caso 30.

CASE SRC TEXT RE FROM_WHOM RESULT ------- ------------------------------- ------------------ ----------------- -------------------------------------------------- -------------- 1 Egor''s original source string A=1,B=2,C=3, .*B=.*?, Egor''s original pattern "doesn''t work" A=1,B=2,C=3, 2 Egor''s original source string A=1,B=2,C=3, .*B=.?, Egor''s "works correctly" A=1,B=2, 3 Egor''s original source string A=1,B=2,C=3, .*B=.+?, Old Pro comment 1 form 2 A=1,B=2, 4 Egor''s original source string A=1,B=2,C=3, .+B=.*?, Old Pro comment 1 form 1 A=1,B=2, 5 Egor''s original source string A=1,B=2,C=3, .*B=.{0,}?, Old Pro comment 2 A=1,B=2, 6 Egor''s original source string A=1,B=2,C=3, [^B]*B=[^Bx]*?, Old Pro answer form 1 "good" A=1,B=2, 7 Egor''s original source string A=1,B=2,C=3, [^B]*B=[^B]*?, Old Pro answer form 2 "bad" A=1,B=2,C=3, 8 Egor''s original source string A=1,B=2,C=3, (.)*B=(.)*?, TBone answer form 1 A=1,B=2, 9 TBone answer example 2 1_@_2_a_3_@_4_a (/w)*?@(/w)* TBone answer example 2 form 1 1_@_2_a_3_ 10 TBone answer example 2 1_@_2_a_3_@_4_a (/w)*@(/w)*? TBone answer example 2 form 2 1_@ 30 Egor''s original source string A=1,B=2,C=3, .*B=(.)*?, Schemaczar Variant to force Perl operation A=1,B=2, 31 Egor''s original source string A=1,B=2,C=3, .*B=(.*)?, Schemaczar Variant of Egor to force POSIX A=1,B=2,C=3, 32 Egor''s original source string A=1,B=2,C=3, .*B=.*{0,1} Schemaczar Applying Egor''s ''non-greedy'' A=1,B=2,C=3, 33 Egor''s original source string A=1,B=2,C=3, .*B=(.)*{0,1} Schemaczar Another variant of Egor''s "non-greedy" A=1,B=2,C=3,

Estoy bastante seguro de que CASE 30 es lo que pensabas que estabas escribiendo, es decir, pensaste que el "*?" Tenía una asociación más fuerte que el "*" por sí mismo. Cierto para Perl, supongo, pero para Oracle (y, presumiblemente, POSIX canónico) RE, el "*?" tiene una precedencia y asociatividad más bajas que "*". ¿Entonces Oracle lo lee como "(. *)?" (caso 31) mientras que Perl lo lee como "(.) *?", es decir, caso 30.

Observe que los casos 32 y 33 indican que "* {0,1}" no funciona como "*?".

Tenga en cuenta que Oracle REGEXP no funciona como LIKE, es decir, no requiere que el patrón de coincidencia cubra toda la cadena de prueba. El uso de los marcadores de inicio "^" y "$" también podrían ayudarlo con esto.


porque tu seleccionas demasiado

SELECT regexp_substr( ''A=1,B=2,C=3,'', ''.*?B=.*?,'' ) as A_and_B, -- Now works as expected regexp_substr( ''A=1,B=2,C=3,'', ''B=.*?,'' ) as B_only -- works just fine FROM dual

Violín de SQL: http://www.sqlfiddle.com/#!4/d41d8/11450