2009-05-12 11 views
20

¿Es posible escribir una expresión regular que devuelva el resultado inverso al deseado? Las expresiones regulares generalmente incluyen: encontrar coincidencias. Quiero poder transformar una expresión regular en su opuesto, afirmando que no hay coincidencias. es posible? ¿Si es así, cómo?Expresión regular opuesta

http://zijab.blogspot.com/2008/09/finding-opposite-of-regular-expression.html estados que se debe a su soporte de expresiones regulares con

/^((?!^ MYREGEX).)*$/ 

, pero esto no parece funcionar. Si tengo expresiones regulares

/[a|b]./ 

, la cadena "abc" devuelve false tanto con mi expresión regular y lo contrario sugerido por zijab,

/^((?!^[a|b].).)*$/ 

. ¿Es posible escribir el recíproco de una expresión regular, o estoy pensando incorrectamente?

+1

¿Qué paquete de expresiones regulares está usando (el idioma que estás trabajando en)? Si su paquete de expresiones regulares no es compatible con un paquete PCRE (RegEx compatible con Perl) bastante moderno, puede ser que simplemente esté malinterpretando el ejemplo de Zijab (la búsqueda negativa de ancho cero). –

Respuesta

6

La razón de su expresión regular invertida no está funcionando se debe a la '^' dentro de la búsqueda negativa hacia delante:

/^((?!^[ab].).)*$/ 
    ^   # WRONG 

Tal vez sea diferente en vim, pero en todos los sabores de expresiones regulares que conozco, la caret coincide con el comienzo de la cadena (o el comienzo de una línea en modo multilínea). Pero creo que fue solo un error tipográfico en la entrada del blog.

También debe tener en cuenta la semántica de la herramienta de expresiones regulares que está utilizando. Por ejemplo, en Perl, esto es cierto:

"abc" =~ /[ab]./ 

Pero en Java, esto no es:

"abc".matches("[ab].") 

Esto se debe a la expresión regular se pasa al método matches() está anclado de manera implícita en ambos extremos (es decir, , /^[ab].$/).

Tomando lo más común, la semántica de Perl, /[ab]./ significa que la cadena de destino contiene una secuencia que consta de un carácter 'a' o 'b' seguido de al menos uno (sin separador de línea). En otras palabras, en CUALQUIER punto, la condición es VERDADERO. El inverso de esa afirmación es que, en CADA punto, la condición es FALSA. Eso significa que, antes de consumir cada personaje, se realiza una búsqueda negativa hacia delante para confirmar que el personaje no es el comienzo de una secuencia coincidente:

(?![ab].). 

Y usted tiene que examinar cada carácter, así, el texto tiene para ser anclado en ambos extremos:

/^(?:(?![ab].).)*$/ 

Esa es la idea general, pero no creo que es posible invertir cada expresiones regulares - no cuando las expresiones regulares originales pueden incluir lookarounds positivos y negativos, reacio y posesivos cuantificadores, y quién sabe s-qué.

11

¿No podría simplemente verificar para ver si no hay coincidencias? No sé qué idioma estás usando, pero ¿qué tal este pseudocódigo?

if (!'Some String'.match(someRegularExpression)) 
    // do something... 

Si sólo se puede cambiar la expresión regular, entonces el que obtuvo de su enlace debería funcionar:

/^((?!REGULAR_EXPRESSION_HERE).)*$/ 
+1

Bueno, ese es el problema. No estoy escribiendo las expresiones regulares o el código. Tengo una aplicación que permite a las personas ingresar sus propias expresiones regulares, y deben ser inclusivas o exclusivas. O bien necesito que ingresen otro dato - inclusivo/exclusivo, o los fuerce a escribirlos de manera inclusiva o exclusiva, usando un patrón 'opuesto', si es que existe alguno.Esto solo lo usarán los programadores, por lo que la complejidad no es una preocupación, solo una posibilidad. – Greg

+1

Hmm, ya veo. Entonces, ¿por qué no funciona esto? /^((?!REGULAR_EXPRESSION_HERE).)*$/ (Tomado de su enlace). Funciona para mí. –

5

Puede invertir el conjunto de caracteres escribiendo un ^ al inicio ([^…]). Entonces, la expresión opuesta de [ab] (coincide con a o b) es [^ab] (no coincide a ni b).

Pero cuanto más compleja sea su expresión, más compleja será también la expresión complementaria. Un ejemplo:

Quiere hacer coincidir el literal foo. Una expresión, que hace coincidir otra cosa que una cadena que contiene foo tendría que corresponde a ninguno de

  1. cualquier cadena que es más corto que foo (^.{0,2}$), o
  2. cualquiera de los tres caracteres de longitud de cadena que no es foo (^([^f]..|f[^o].|fo[^o])$) o
  3. cadena más larga que no contiene foo.

Todos juntos esto puede funcionar:

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

Pero Nota: Esto sólo se aplica a foo.

2

También puede hacer esto (en Python) mediante el uso de re.split, y la división basada en la expresión regular, volviendo así todas las partes que no coinciden con la expresión regular, how to find the converse of a regex

1

en Perl que puede anti-partido con $string !~ /regex/;.

0

Con grep, puede usar --invert-match o -v.

0

Java Regexps tiene una forma interesante de hacerlo (puede probar here) donde puede crear una coincidencia codiciosa opcional para la cadena que desee, y luego unir los datos después de ella. Si la coincidencia codiciosa falla, es opcional, por lo que no importa, si tiene éxito, necesita algunos datos adicionales para que coincida con la segunda expresión y, por lo tanto, falla.

Parece contraintuitivo, pero funciona.

Ej (foo)?+.+ coincide bar, foox y xfoo pero no coincidirá foo (o una cadena vacía).

Podría ser posible en otros dialectos, pero no pudo conseguir que funcione a mí mismo (que parecen más dispuestos a dar marcha atrás si el segundo partido no?)