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).
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.
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?
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.
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)
¡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.
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.
Probablemente quieras mencionar que necesitas unirte nuevamente.
tomdemuyt
Se está utilizando un enfoque similar replacestr.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:
findstr
etiqueta ya que todas las respuestas aquí no son válidas para la etiqueta.Respuestas:
Podría usar una afirmación de anticipación:
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:
Esto también coincide con cualquier secuencia de tres dígitos que no lo sea
999
.fuente
Si desea hacer coincidir una palabra A en una cadena y no hacer coincidir una palabra B. Por ejemplo: si tiene un texto:
Si desea buscar líneas de texto que TENGAN un perro como mascota y NO tiene gato , puede usar esta expresión regular:
Encontrará solo la segunda línea:
fuente
findstr
comando 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 .)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.
fuente
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 ).
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 ...
fuente
\d
con[[: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".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.fuente
patrón - re
devolverá todo excepto el patrón.
Prueba aquí
fuente
replace
str.replace(/re/g, '')
, entonces no hay necesidad de volver a unirse a ellos. ¿también si arrojas un buen seguimiento? comostr.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 cadenaMi respuesta aquí también podría resolver su problema:
https://stackoverflow.com/a/27967674/543814
$1
, leerías grupo$2
.$2
se 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
,.fuente
luego usa lo que el grupo 2 captura ...
fuente