not negative exclude regex regex-negation

negative - Regex: Emparejamiento por exclusión, sin mirar hacia adelante-¿es posible?



regex not character (3)

En algunos sabores de expresiones regulares, las aserciones [negativas] de ancho cero (mirar hacia adelante / mirar hacia atrás) no son compatibles.

Esto hace que sea extremadamente difícil (¿imposible?) Establecer una exclusión. Por ejemplo, "cada línea que no tiene" foo "en ella", así:

^((?!foo).)*$

¿Se puede lograr lo mismo sin utilizar la mirada en todo (preocupaciones de complejidad y rendimiento dejadas de lado por el momento)?


Por lo general, puede buscar foo e invertir el resultado de la coincidencia de expresiones regulares del código del cliente.

Para un ejemplo simple, supongamos que quiere validar que una cadena contiene solo ciertos caracteres.

Podrías escribir eso así:

^[A-Za-z0-9.$-]*$

y acepta un resultado true como válido, o como este:

[^A-Za-z0-9.$-]

y acepta un resultado false como válido.

Por supuesto, esto no siempre es una opción: a veces solo tienes que poner la expresión en un archivo de configuración o pasarla a otro programa, por ejemplo. Pero vale la pena recordar Su problema específico, por ejemplo, la expresión es mucho más simple si puede usar una negación como esta.


Me encontré con esta pregunta buscando mi propia solución de exclusión de expresiones regulares, donde estoy tratando de excluir una secuencia dentro de mi expresión regular.

Mi reacción inicial ante esta situación: por ejemplo, "cada línea que no tiene" foo "en ella" era simplemente para usar la opción -v invertir el sentido de coincidencia en grep.

grep -v foo

esto devuelve todas las líneas en un archivo que no coincide con ''foo''

Es tan simple que tengo la fuerte sensación de que acabo de leer mal tu pregunta ...


ACTUALIZACIÓN: falla "con dos ff antes de oo", como señaló @Ciantic en los comentarios.

^(f(o[^o]|[^o])|[^f])*$

NOTA: es mucho más fácil simplemente negar una coincidencia en el lado del cliente en lugar de usar la expresión regular anterior.

La expresión regular asume que cada línea termina con una char de nueva línea si no es así y luego ve las expresiones regulares de C ++ y grep.

Los programas de muestra en Perl, Python, C ++ y grep proporcionan el mismo resultado.

  • Perl

    #!/usr/bin/perl -wn print if /^(f(o[^o]|[^o])|[^f])*$/;

  • pitón

    #!/usr/bin/env python import fileinput, re, sys from itertools import ifilter re_not_foo = re.compile(r"^(f(o[^o]|[^o])|[^f])*$") for line in ifilter(re_not_foo.match, fileinput.input()): sys.stdout.write(line)

  • c ++

    #include <iostream> #include <string> #include <boost/regex.hpp> int main() { boost::regex re("^(f(o([^o]|$)|([^o]|$))|[^f])*$"); //NOTE: "|$"s are there due to `getline()` strips newline char std::string line; while (std::getline(std::cin, line)) if (boost::regex_match(line, re)) std::cout << line << std::endl; }

  • grep

    $ grep "^/(f/(o/([^o]/|$/)/|/([^o]/|$/)/)/|[^f]/)*$" in.txt

Archivo de muestra:

foo ''foo'' abdfoode abdfode abdfde abcde f fo foo fooo ofooa ofo ofoo

Salida:

abdfode abdfde abcde f fo ofo