Todas las cosas buenas son tres (¿cómo omitir las subcoincidencias no deseadas?)

¿Cómo consumir/saltar coincidencias no deseadas?

Supongamos que tenemos el siguiente texto:

my $t ='good good *bad !bad -bad "alwaysbad alwaysbad alwaysbad" good';

y me gustaría tener una sola expresión regular que coincida solo good palabras. El contenido real de las palabras simbólicas good, bad y alwaysbad es, por supuesto, [0-9A-Za-z_@]+ (\w+ está bien para esta pregunta). para decirle a un bad palabra de un good uno, algo como (\s|^)\b\w al comienzo de la palabra sería suficiente. Las cosas entre comillas dobles siempre son una mala palabra, incluso si no están prefijadas.

Esto es lo que tengo:

my $r = qr/
           (?: " [^"]+ " )     # skip quoted part altogether, don't capture
            |                  # OR
           (?<!\S) \b ([\w@]+) # find words without 'bad' prefix and capture
          /x;

esta expresión no capturaría la parte citada, pero aun así coincidiría. Por lo tanto, tendremos un undefined entrada vacía en la lista de coincidencias:

my @matches = $t =~ /$r/g;

print join "\n", @matches;

  good
  good
         <== (uninitialized value, this comes from the quoted part)
  good

Ahora la pregunta:

¿Alguien conoce una técnica aplicable a las expresiones regulares perl contemporáneas? cómo consumir una parte dada de una cadena pero no igualarla con una sola invocación de expresiones regulares?

El resultado debe ser, por tanto:

  good
  good
  good


Apéndice:

Gracias a Respuesta de borodin, lo veo más claro ahora. Con solo quitar el | (o) y aplicando cualquier or-zero-times cuantificador, funcionará:

my $r = qr/
           (?: " [^"]+ ")? \s?  # skip quotes + space if any
           (?<!\S) \b ([\w@]+)  # find words without 'bad' prefix and capture
          /x;

preguntado el 31 de julio de 12 a las 12:07

2 Respuestas

Su expresión regular solo coincide con la secuencia que no captura porque ha dicho que eso es lo que quería.

Escriba un prefijo opcional de cualquier número de cadenas entre comillas con caracteres intermedios sin comillas, como este

my $r = qr/
  (?: " [^"]* " [^"]*?)*    # skip quoted part altogether, don't capture
  (?<!\S) \b (\w+)          # find words without 'bad' prefix and capture
/x;

Pero para mayor claridad, optaría por eliminar todas las cadenas citadas del objetivo antes de intentar hacer coincidirlo. No olvides que si quieres permitir @ también en tus subcadenas, entonces necesitas [\w@]. Y también necesita una verificación final para asegurarse de que no haya caracteres no válidos después de el principio.

$t =~ s/"[^"]*"//g;
my @matches = $t =~ /(?:\s|^)[\w\@]+(?=\s|\z)/g;

Respondido 31 Jul 12, 13:07

Oo, estaba completamente estupefacto por la parte citada. Por supuesto, uno puede simplemente omitir cualquier parte bien definida aplicando el * cuantificador a todo el subpatrón. Es hora de hacer más trabajo de expresiones regulares nuevamente, ¡jeje! ¡Gracias! - botas de goma

Podrías simplemente filtrarlos:

my @matches = grep { m/\S/ } $t =~ /$r/g;

Respondido 31 Jul 12, 13:07

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.