Regex: cómo hacer coincidir todo excepto un patrón en particular


171

¿Cómo escribo una expresión regular para que coincida con cualquier cadena que no cumpla con un patrón en particular? Me enfrento a una situación en la que tengo que hacer coincidir un patrón (A y ~ B).


PCRE sería lo mejor para esto: vea Regex Pattern to Match, excluyendo cuando ... / Excepto entre . Eliminé la findstretiqueta ya que todas las respuestas aquí no son válidas para la etiqueta.
Wiktor Stribiżew

Respuestas:


192

Podría usar una afirmación de anticipación:

(?!999)\d{3}

Este ejemplo coincide con tres dígitos distintos de 999.


Pero si no tiene una implementación de expresión regular con esta característica (vea Comparación de sabores de expresión regular ), probablemente tenga que construir una expresión regular con las características básicas por su cuenta.

Una expresión regular compatible con sintaxis básica solo sería:

[0-8]\d\d|\d[0-8]\d|\d\d[0-8]

Esto también coincide con cualquier secuencia de tres dígitos que no lo sea 999.


1
Look-ahead no es una sintaxis de expresión regular estándar, es una extensión Perl, solo funcionará en Perl, PCRE (Perl-Compatible RegEx) u otras implementaciones no estándar
Juliano

10
Puede que no sea estándar, pero ¿la mayoría de los idiomas modernos no lo admiten? ¿Qué idioma no admite look-aheads en estos días?
Bryan Oakley

1
Es verdad. Pero la mayoría de los sabores de expresiones regulares admiten esta función (consulte < regular-expressions.info/refflavors.html> ).
Gumbo

1
Creo que la última expresión regular tampoco coincidiría con 009, 019 ... etc.
Sebastian Viereck

1
Lex estándar para C no utiliza PCRE :-(
pieman72

30

Si desea hacer coincidir una palabra A en una cadena y no hacer coincidir una palabra B. Por ejemplo: si tiene un texto:

1. I have a two pets - dog and a cat
2. I have a pet - dog

Si desea buscar líneas de texto que TENGAN un perro como mascota y NO tiene gato , puede usar esta expresión regular:

^(?=.*?\bdog\b)((?!cat).)*$

Encontrará solo la segunda línea:

2. I have a pet - dog

No pudo mencionarlo en la pregunta, pero el OP está usando el findstrcomando DOS . Ofrece solo un pequeño subconjunto de las capacidades que espera encontrar en una herramienta de expresiones regulares; La búsqueda anticipada no está entre ellos. (Acabo de agregar la etiqueta findtr .)
Alan Moore

2
hm, sí, encontré ahora en uno de sus comentarios en las publicaciones. Vi Regex en el título. De todos modos, si alguien encuentra esta publicación cuando busca la misma expresión regular, como lo hice, tal vez podría ser útil para alguien :) gracias por los comentarios
Aleks

15

Haga coincidir el patrón y use el idioma del host para invertir el resultado booleano de la coincidencia. Esto será mucho más legible y mantenible.


1
Luego acabo con (~ A o B) en lugar de (A y ~ B). No resuelve mi problema.
no es

1
Pseudocódigo: String toTest; if (toTest.matches (A) AND! toTest.matches (B)) {...}
Ben S

Debería haber sido más claro: las piezas no son completamente independientes. Si A coincide con parte de la cadena, entonces nos importa si ~ B coincide con el resto (pero no necesariamente con todo). Esto fue para la función de búsqueda de la línea de comandos de Windows, que encontré está restringida a expresiones regulares verdaderas, por lo que es discutible.
no es

8

no, resucitar esta antigua pregunta porque tenía una solución simple que no se mencionó. (Encontré tu pregunta mientras investigabas para una búsqueda de recompensas de expresiones regulares ).

Me enfrento a una situación en la que tengo que hacer coincidir un patrón (A y ~ B).

La expresión regular básica para esto es terriblemente simple: B|(A)

Simplemente ignore las coincidencias generales y examine las capturas del Grupo 1, que contendrán A.

Un ejemplo (con todas las renuncias sobre el análisis de HTML en expresiones regulares): A son dígitos, B son dígitos dentro de <a tag

La expresión regular: <a.*?<\/a>|(\d+)

Demostración (mire el Grupo 1 en el panel inferior derecho)

Referencia

Cómo hacer coincidir el patrón, excepto en las situaciones s1, s2, s3

Cómo hacer coincidir un patrón a menos que ...


¡Suena demasiado bueno para ser cierto! Desafortunadamente, esta solución no es universal y falla en Emacs, incluso después de reemplazar \dcon [[:digit:]]. La primera referencia menciona que es específica de Perl y PHP: "Existe una variación que usa la sintaxis específica de Perl y PHP que logra lo mismo".
miguelmorin

4

El complemento de un lenguaje regular también es un lenguaje regular, pero para construirlo debe construir el DFA para el lenguaje regular y hacer que cualquier cambio de estado válido se convierta en un error. Vea esto para un ejemplo. Lo que la página no dice es que se convirtió /(ac|bd)/en /(a[^c]?|b[^d]?|[^ab])/. La conversión de un DFA a una expresión regular no es trivial. Es más fácil si puede usar la expresión regular sin cambios y cambiar la semántica en el código, como se sugirió anteriormente.


2
Si estuviera tratando con expresiones regulares reales, todo esto sería discutible. Regex ahora parece referirse al nebuloso espacio CSG-ish (?) De coincidencia de patrones que admite la mayoría de los idiomas. Como necesito hacer coincidir (A y ~ B), no hay forma de eliminar la negación y aún hacerlo todo en un solo paso.
no el

Lookahead, como se describió anteriormente, lo habría hecho si findtr hizo algo más que verdaderas expresiones regulares de DFA. Todo esto es un poco extraño y no sé por qué tengo que hacer este estilo de línea de comandos (lote ahora). Es solo otro ejemplo de mis manos atadas.
no el

1
@notnot: ¿Está utilizando findtr de Windows? Entonces solo necesitas / v. Como: encuentra un archivo de entrada | findtr / v B> outputfile.txt La primera coincide con todas las líneas con A, la segunda coincide con todas las líneas que no tienen B.
Juliano

¡Gracias! Eso es exactamente lo que necesitaba. Sin embargo, no hice la pregunta de esa manera, así que todavía le doy la respuesta a Gumbo por la respuesta más generalizada.
no el

1

patrón - re

str.split(/re/g) 

devolverá todo excepto el patrón.

Prueba aquí


Probablemente quieras mencionar que necesitas unirte nuevamente.
tomdemuyt

Se está utilizando un enfoque similar replace str.replace(/re/g, ''), entonces no hay necesidad de volver a unirse a ellos. ¿también si arrojas un buen seguimiento? como str.replace(/\re\s?/g, '')continuación a deshacerse de los espacios duplicados que tendría que partir de algo que se sustituye en el medio de una cadena
jakecraige

0

Mi respuesta aquí también podría resolver su problema:

https://stackoverflow.com/a/27967674/543814

  • En lugar de Reemplazar, usaría Match.
  • En lugar de grupo $1, leerías grupo $2.
  • El grupo $2se hizo sin captura allí, lo que evitarías.

Ejemplo:

Regex.Match("50% of 50% is 25%", "(\d+\%)|(.+?)");

El primer grupo de captura especifica el patrón que desea evitar. El último grupo de captura captura todo lo demás. Simplemente lea ese grupo $2,.


0
(B)|(A)

luego usa lo que el grupo 2 captura ...


Necesita capturar no B, su objetivo no es simplemente ignorar todos los patrones B.
hexicle
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.