¿Cómo hacer una "coincidencia inversa" con expresiones regulares?

112

Estoy usando RegexBuddy pero de todos modos tengo problemas con esto: \

Estoy procesando línea por línea un archivo. Construí un "modelo de línea" para que coincida con lo que quiero.

Ahora me gustaría hacer una coincidencia inversa ... es decir, quiero hacer coincidir líneas donde hay una cadena de 6 letras, pero solo si estas seis letras no son Andrea , ¿cómo debo hacer eso?


EDITAR: Escribiré el programa que usa esta expresión regular, todavía no sé si en python o php, estoy haciendo esto primero para aprender algunas expresiones regulares :) Hay diferentes tipos de línea, quería usar expresiones regulares para seleccionar el tipo que me interesa. Una vez que obtengo estas líneas, debo aplicar otro filtro para que no coincida con un valor conocido, necesito todos los demás, no ese. El (?! No deseado) funciona bastante bien, gracias. :-)

Espero que esto aclare la pregunta :)

Andrea Ambu
fuente
De hecho, parece que sería mejor que nos brinde un poco más de información sobre lo que está haciendo y vea si alguien puede ofrecer una solución alternativa. Por lo general, intentar analizar un archivo completo mediante la construcción de una expresión regular que coincida con cada línea es una ruta bastante complicada :)
Dan

Respuestas:

70
(?!Andrea).{6}

Suponiendo que su motor de expresiones regulares admita búsquedas anticipadas negativas ...

Editar: ... o tal vez prefiera usar [A-Za-z]{6}en lugar de.{6}

Editar (nuevamente): tenga en cuenta que las búsquedas anticipadas y retrospectivas generalmente no son la manera correcta de "invertir" una coincidencia de expresión regular. Las expresiones regulares no están realmente configuradas para hacer coincidencias negativas, lo dejan en cualquier idioma con el que las esté usando.

Dan
fuente
Debes agregar el ^ que @Vinko Vrsalovic usa para que no coincida en "ndrea \ n"
bdukes
2
. no coincide con \ n de forma predeterminada (algunos idiomas [por ejemplo, Perl] le permiten activar ese comportamiento, pero de forma predeterminada. coincide con todo PERO \ n).
Dan
1
(además, el OP nunca mencionó que la cadena tenía que ocurrir al comienzo de la línea)
Dan
1
¿Qué quieres decir con OP?
Andrea Ambu
1
Andrea: OP significa "póster original", así que me refería a ti :)
Dan
47

Para Python / Java,

^(.(?!(some text)))*$

http://www.lisnichenko.com/articles/javapython-inverse-regex.html

Dmytro
fuente
4
Esto no funciona. Estás pensando en el idioma Tempered Greedy Token. pero el punto tiene que ir después de la búsqueda anticipada, no antes. Vea esta pregunta . Pero ese enfoque es excesivo para esta tarea de todos modos.
Alan Moore
No sé en qué idioma está escrito, pero funcionó como un encanto en Sublime text para limpiar los datos de mi prueba. ¡Gracias!
Matthias dirickx
1
@AlanMoore En realidad, casi funcionará para este caso de uso. Sin embargo, si some textcomienza la línea, devolverá el resultado incorrecto.
Zenexer
2
@Zenexer, eso es lo que quise decir. Si el punto está después de la búsqueda anticipada en lugar de antes, funciona perfectamente.
Alan Moore
Aquí hay un enlace que explica más. No entiendo por qué ?!y no solo !.
Timo
21

Actualizado con comentarios de Alan Moore

En PCRE y variantes similares, puede crear una expresión regular que coincida con cualquier línea que no contenga un valor:

^(?:(?!Andrea).)*$

A esto se le llama una muestra codiciosa templada . La desventaja es que no funciona bien.

Zenexer
fuente
1
Esta es la Ficha Codiciosa Templada en forma larga. Sólo hay que poner el punto (o [\s\S], lo que sólo es útil en JavaScript) después de la segunda búsqueda hacia delante, y que no es necesario la primera de ellas: ^(?:(?!Andrea).)*$.
Alan Moore
@AlanMoore ¡Agradable! No pude encontrar ningún patrón establecido que funcionara así, así que se me ocurrió el mío. En lugar de que yo tome su respuesta, debe proporcionarla como propia.
Zenexer
Está bien, ya hay muchas buenas respuestas. Y mereces crédito por haber inventado el idioma por tu cuenta. ¡Salud!
Alan Moore
¿Por qué sugieres usar [\S\s]? OP está hablando de líneas coincidentes, sin contener la palabra "Andrea". No se trata de comprobar si toda la cadena contiene esta palabra. ¿Me estoy perdiendo de algo?
x-yuri
@ x-yuri creo que tienes razón. Probablemente respondí a la pregunta que tenía: visité esta página por primera vez, ignorando la discrepancia. Sin embargo, mi conexión no es lo suficientemente buena para actualizar la respuesta en este momento (<10 kbps)
Zenexer
11

Qué idioma estás usando? Las capacidades y la sintaxis de la implementación de expresiones regulares son importantes para esto.

Podría utilizar la anticipación. Usando Python como ejemplo

import re

not_andrea = re.compile('(?!Andrea)\w{6}', re.IGNORECASE)

Para desglosar eso:

(?! Andrea) significa 'coincidir si los siguientes 6 caracteres no son "Andrea"'; si es así entonces

\ w significa un "carácter de palabra": caracteres alfanuméricos. Esto es equivalente a la clase [a-zA-Z0-9_]

\ w {6} significa exactamente 6 caracteres de palabra.

re.IGNORECASE significa que excluirá a "Andrea", "andrea", "ANDREA" ...

Otra forma es usar la lógica de su programa: use todas las líneas que no coincidan con Andrea y póngalas en una segunda expresión regular para verificar 6 caracteres. O primero verifique que haya al menos 6 caracteres de palabras y luego verifique que no coincida con Andrea.

Hamish Downer
fuente
7

Afirmación de anticipación negativa

(?!Andrea)

Esta no es exactamente una coincidencia invertida, pero es lo mejor que puede hacer directamente con expresiones regulares. Sin embargo, no todas las plataformas los admiten.

Vinko Vrsalovic
fuente
1
Hasta que el interlocutor aclare, no veo que el partido deba comenzar desde el principio de la línea. Entonces, ¿por qué ^?
Hamish Downer
Porque entendí que quería verificar al principio de la línea, editado dadas las aclaraciones
Vinko Vrsalovic
5

Si desea hacer esto en RegexBuddy, hay dos formas de obtener una lista de todas las líneas que no coinciden con una expresión regular.

En la barra de herramientas del panel Prueba, establezca el alcance de la prueba en "Línea por línea". Cuando lo haga, aparecerá un elemento Listar todas las líneas sin coincidencias debajo del botón Listar todas en la misma barra de herramientas. (Si no ve el botón Mostrar todo, haga clic en el botón Coincidir en la barra de herramientas principal).

En el panel GREP, puede activar las casillas de verificación "basado en líneas" e "invertir resultados" para obtener una lista de líneas que no coinciden en los archivos que está revisando.

Jan Goyvaerts
fuente
5

(?!es útil en la práctica. Aunque estrictamente hablando, mirar hacia el futuro no es una expresión regular como se define matemáticamente.

Puede escribir una expresión regular invertida manualmente.

Aquí hay un programa para calcular el resultado automáticamente. Su resultado es generado por máquina, que suele ser mucho más complejo que escribir uno a mano. Pero el resultado funciona.

debilitado
fuente
1

Se me acaba de ocurrir este método que puede ser intensivo en hardware pero está funcionando:

Puede reemplazar todos los caracteres que coincidan con la expresión regular por una cadena vacía.

Este es un delineador:

notMatched = re.sub(regex, "", string)

Usé esto porque me vi obligado a usar una expresión regular muy compleja y no pude averiguar cómo invertir cada parte de ella en un período de tiempo razonable.

Esto solo le devolverá el resultado de la cadena, ¡no ningún objeto coincidente!

Matthias Herrmann
fuente
-3

En perl puedes hacer

proceso ($ línea) if ($ línea = ~! / Andrea /);

phreakre
fuente
4
Esa sintaxis es incorrecta. Creo que te refieres al proceso ($ línea) si $ línea! ~ / Andrea /
dland