reuse regular patterns online non negative how expressions example capturing python regex perl regex-lookarounds

python - regular - Negativa Lookahead Regex codicia(¿por qué es.*? Demasiado codicioso)



regular expression (3)

Si tiene curiosidad sobre lo que Perl está haciendo con una expresión regular, puede ejecutar con el depurador de expresiones regulares:

perl -Dr -e ''"A two. A one." =~ /(?![A-Z][^/.]*(?:two)[^/.]*/.)([A-Z][^/.]+/.)/; print ">$1</n"''

Lo que generará mucha salida para que lo medites. Necesitará un Perl construido con -DDEBUGGING.

Tengo problemas para entender los detalles más finos de las expresiones regulares negativas de cabecera. Después de leer la búsqueda de expresiones regulares, los grupos atómicos y los de la mente , pensé que tenía un buen resumen de las perspectivas negativas cuando encontré esta descripción:

(?!REGEX_1)REGEX_2

Coincidir solo si REGEX_1 no coincide; después de marcar REGEX_1 , la búsqueda de REGEX_2 comienza en la misma posición.

Con la esperanza de que entendiera el algoritmo, cociné un insulto de prueba de dos oraciones; Quería encontrar la oración sin una palabra determinada. Específicamente...

Insulto: ''Yomama es fea. Y, ella huele como un perro mojado.

Requisitos :

  • Prueba 1: Devuelve una oración sin ''feo''.
  • Prueba 2: Devuelve una oración sin ''looks''.
  • Prueba 3: Devuelve una oración sin ''olores''.

Asigné las palabras de prueba a $arg , y utilicé (?:(?![AZ].*?$arg.*?/.))([AZ].*?/.) Para implementar la prueba.

  • (?![AZ].*?$arg.*?/.) Es un aspecto negativo para rechazar una oración con la palabra de prueba
  • ([AZ].*?/.) Coincide con al menos una oración.

La pieza crítica parece estar en entender dónde el motor de expresiones regulares comienza a coincidir después de procesar el lookahead negativo.

Resultados esperados :

  • Prueba 1 ($ arg = "feo"): "Y, ella huele como un perro mojado".
  • Prueba 2 ($ arg = "looks"): "Yomama es fea".
  • Prueba 3 ($ arg = "huele"): "Yomama es fea".

Resultados reales :

  • Prueba 1 ($ arg = "feo"): "Y, ella huele como un perro mojado". (Éxito)
  • Prueba 2 ($ arg = "looks"): "Yomama es fea". (Éxito)
  • Prueba 3 ($ arg = "huele"): Falló, no coincide

Al principio pensé que la Prueba 3 había fallado porque ([AZ].*?/.) Era demasiado codicioso y combinaba ambas oraciones; sin embargo, (?:(?![AZ].*?$arg.*?/.))([AZ][^/.]*?/.) tampoco funcionó. A continuación, me pregunté si había un problema con la implementación negativa de Python lookahead, pero Perl me dio exactamente el mismo resultado.

Finalmente encontré la solución, tuve que rechazar puntos en mi .*? porción de las expresiones usando [^/.]*? ; así que esta expresión regular funciona: (?:(?![AZ][^/.]*?$arg[^/.]*?/.))([AZ][^/.]*?/.)

Pregunta

Sin embargo, tengo otra preocupación; "Yomama es fea". No tiene "olores" en ella. Entonces, si .*? se supone que es un partido no codicioso, ¿por qué no puedo completar la prueba 3 con (?:(?![AZ].*?$arg.*?/.))([AZ].*?/.) ?

EDITAR

A la luz de la excelente sugerencia de @ bvr de usar -Mre=debug , consideraré esto un poco más después del trabajo. Ciertamente parece que la descripción de Seth es precisa en este punto. Lo que aprendí hasta ahora es que las expresiones de lookahead negativas coincidirán siempre que sea posible, incluso si las pongo no codiciosas .*? Operadores en la NLA.

Implementación Python

import re def test_re(arg, INSULTSTR): mm = re.search(r'''''' (?: # No grouping (?![A-Z].*?%s.*?/.)) # Negative zero-width # assertion: arg, followed by a period ([A-Z].*?/.) # Match a capital letter followed by a period '''''' % arg, INSULTSTR, re.VERBOSE) if mm is not None: print "neg-lookahead(%s) MATCHED: ''%s''" % (arg, mm.group(1)) else: print "Unable to match: neg-lookahead(%s) in ''%s''" % (arg, INSULTSTR) INSULT = ''Yomama is ugly. And, she smells like a wet dog.'' test_re(''ugly'', INSULT) test_re(''looks'', INSULT) test_re(''smells'', INSULT)

Implementación Perl

#!/usr/bin/perl sub test_re { $arg = $_[0]; $INSULTSTR = $_[1]; $INSULTSTR =~ /(?:(?![A-Z].*?$arg.*?/.))([A-Z].*?/.)/; if ($1) { print "neg-lookahead($arg) MATCHED: ''$1''/n"; } else { print "Unable to match: neg-lookahead($arg) in ''$INSULTSTR''/n"; } } $INSULT = ''Yomama is ugly. And, she smells like a wet dog.''; test_re(''ugly'', $INSULT); test_re(''looks'', $INSULT); test_re(''smells'', $INSULT);

Salida

neg-lookahead(ugly) MATCHED: ''And, she smells like a wet dog.'' neg-lookahead(looks) MATCHED: ''Yomama is ugly.'' Unable to match: neg-lookahead(smells) in ''Yomama is ugly. And, she smells like a wet dog.''


Su problema es que el motor de expresiones regulares se esforzará lo más posible por coincidir (?![AZ].*?$arg.*?/.) , Por lo que con el caso de "olores", termina por coincidir con toda la cadena. (El período en el medio se incluye en una de las construcciones .*? ). Debe restringir el caso de búsqueda anticipada negativa para que coincida solo con lo que el otro caso puede:

En lugar de:

(?:(?![A-Z].*?$arg.*?/.))([A-Z].*?/.)

Utilizar:

(?:(?![A-Z][^.]*$arg[^.]*/.))([A-Z].*?/.)

Ahora, el lookahead negativo no puede coincidir más de la cadena que la otra parte, ya que debe detenerse en el primer período.


#!/usr/bin/perl sub test_re { $arg = $_[0]; $INSULTSTR = $_[1]; $INSULTSTR =~ /(?:^|/./s*)(?:(?![^.]*?$arg[^.]*/.))([^.]*/.)/; if ($1) { print "neg-lookahead($arg) MATCHED: ''$1''/n"; } else { print "Unable to match: neg-lookahead($arg) in ''$INSULTSTR''/n"; } } $INSULT = ''Yomama is ugly. And, she smells like an wet dog.''; test_re(''Yomama'', $INSULT); test_re(''ugly'', $INSULT); test_re(''looks'', $INSULT); test_re(''And'', $INSULT); test_re(''And,'', $INSULT); test_re(''smells'', $INSULT); test_re(''dog'', $INSULT);

Resultados:

neg-lookahead(Yomama) MATCHED: ''And, she smells like an wet dog.'' neg-lookahead(ugly) MATCHED: ''And, she smells like an wet dog.'' neg-lookahead(looks) MATCHED: ''Yomama is ugly.'' neg-lookahead(And) MATCHED: ''Yomama is ugly.'' neg-lookahead(And,) MATCHED: ''Yomama is ugly.'' neg-lookahead(smells) MATCHED: ''Yomama is ugly.'' neg-lookahead(dog) MATCHED: ''Yomama is ugly.''