Coincidir con todo excepto las cadenas especificadas

118

Sé que la siguiente expresión regular coincidirá con "rojo", "verde" o "azul".

red|green|blue

¿Existe una forma sencilla de hacer que coincida con todo excepto con varias cadenas especificadas?

Alfredo
fuente
1
No todos los tipos de expresiones regulares pueden hacer esto. ¿En qué entorno estás trabajando? ¿Java? Perl? .¿RED? ¿Alguna biblioteca de expresiones regulares C / C ++? ¿Un RDBMS?
FrustratedWithFormsDesigner
8
No dice para qué lo quiere, pero simplemente puede invertir el sentido de la operación "emparejar". Esto no lo ayudará si está tratando de extraer las partes que no coinciden, pero para probar si una cadena excluida no está presente, funcionaría: if (!s.match(/red|green|blue/)) ... Nota: Sé que el OP no especifica qué idioma / marco, por lo que lo anterior debe considerarse un ejemplo genérico, no prescriptivo.
tvanfosson

Respuestas:

153

Si desea asegurarse de que la cadena no sea roja, verde ni azul, la respuesta de caskey es. Sin embargo, lo que a menudo se desea es asegurarse de que la línea no contenga rojo, verde o azul en ninguna parte. Para eso, ancle la expresión regular ^e incluya .*en la búsqueda anticipada negativa:

^(?!.*(red|green|blue))

Además, suponga que desea líneas que contengan la palabra "motor" pero sin ninguno de esos colores:

^(?!.*(red|green|blue)).*engine

Podría pensar que puede factorizar el .*al principio de la expresión regular:

^.*(?!red|green|blue)engine     # Does not work

pero no puedes. Debe tener ambas instancias de .*para que funcione.

Wayne Conrad
fuente
48

Depende del idioma, pero generalmente hay afirmaciones negativas que puede incluir así:

(?!red|green|blue)

(Gracias por la corrección de sintaxis, lo anterior es válido para Java y Perl, YMMV)

caskey
fuente
2
@caskey, la respuesta completa es una combinación mía y tuya. Si desea fusionarlos, eliminaré el mío.
Wayne Conrad
13
Esta respuesta sería mucho más útil si la explicaras un poco. Por ejemplo: ¿Qué hago "?" y "!" ¿media? ¿Por qué necesita grupos de captura?
Lii
También es un Python válido.
Joe Mornin
solo usé esto con la biblioteca regEx de Delphi y solo funciona así: ^ (?! rojo | verde | azul). También es cierto para probarlo en regex101.com . Entonces, ¿falta un ^ o en realidad funciona así en Java / Perl / Python ..?
Peter
32

Coincidir con cualquier cosa menos cadenas dadas

Si desea hacer coincidir toda la cadena donde desea hacer coincidir todo menos ciertas cadenas, puede hacerlo así:

^(?!(red|green|blue)$).*$

Esto dice, comience la coincidencia desde el principio de la cadena donde no puede comenzar y terminar con rojo, verde o azul y haga coincidir cualquier otra cosa con el final de la cadena.

Puedes probarlo aquí: https://regex101.com/r/rMbYHz/2

Tenga en cuenta que esto solo funciona con motores de expresiones regulares que admiten una búsqueda anticipada negativa .

Sam
fuente
23

No necesitas una mirada hacia delante negativa. Hay un ejemplo de trabajo:

/([\s\S]*?)(red|green|blue|)/g

Descripción:

  • [\s\S] - coincidir con cualquier personaje
  • * - partido de 0 a ilimitado del grupo anterior
  • ? - emparejar lo menos posible
  • (red|green|blue|) - coincidir con una de estas palabras o nada
  • g - patrón de repetición

Ejemplo:

whiteredwhiteredgreenbluewhiteredgreenbluewhiteredgreenbluewhiteredgreenbluewhiteredgreenbluewhiteredgreenbluewhiteredgreenbluewhiteredwhiteredwhiteredwhiteredwhiteredwhiteredgreenbluewhiteredwhiteredwhiteredwhiteredwhiteredredgreenredgreenredgreenredgreenredgreenbluewhiteredbluewhiteredbluewhiteredbluewhiteredbluewhiteredwhite

Estarán:

whitewhitewhitewhitewhitewhitewhitewhitewhitewhitewhitewhitewhitewhitewhitewhitewhitewhitewhitewhitewhitewhitewhitewhitewhite

Pruébalo: regex101.com

hlcs
fuente
4
Puede reducir drásticamente el recuento de pasos cambiando [\ s \ S] por un punto. Estaba muy confundido por qué aparentemente todos los demás ejemplos capturan cada palabra individualmente. De esta manera, hay pasos ligeramente más regex, pero requiere mucho menos procesamiento posterior.
Zatronium
3
pero esto no coincide (validación de texto), simplemente elimina el texto especificado durante la sustitución.
Marek R
Esta solución no generará el fragmento final de texto después de las palabras conocidas. Por lo tanto, no es necesario comparar la velocidad, simplemente está mal.
Wiktor Stribiżew
@ WiktorStribiżew arreglado.
hlcs
10

Tenía la misma pregunta, las soluciones propuestas estaban casi funcionando pero tenían algún problema. Al final, la expresión regular que utilicé es:

^(?!red|green|blue).*

Lo probé en Javascript y .NET.

. * no debe colocarse dentro de la búsqueda anticipada negativa de esta manera: ^ (?!. * rojo | verde | azul) o haría que el primer elemento se comporte de manera diferente al resto (es decir, "otro rojo" no coincidiría mientras " otro verde "lo haría)

Durden81
fuente
3

Hacer coincidir cualquier texto, excepto los que coinciden con un patrón, generalmente se logra dividiendo la cadena con el patrón de expresiones regulares .

Ejemplos :

  • - Regex.Split(text, @"red|green|blue")o, para deshacerse de los valores vacíos, Regex.Split(text, @"red|green|blue").Where(x => !string.IsNullOrEmpty(x))(ver demostración )
  • - Regex.Split(text, "red|green|blue")o, para eliminar elementos vacíos, Regex.Split(text, "red|green|blue").Where(Function(s) Not String.IsNullOrWhitespace(s))(ver demostración , o esta demostración donde se admite LINQ)
  • - text.split(/red|green|blue/)(¡no es necesario usar el gmodificador aquí!) (para deshacerse de los valores vacíos, use text.split(/red|green|blue/).filter(Boolean)), vea la demostración
  • - text.split("red|green|blue"), o - para mantener todos los elementos vacíos finales - use text.split("red|green|blue", -1), o para eliminar todos los elementos vacíos use más código para eliminarlos (ver demostración )
  • - Similar a Java, text.split(/red|green|blue/)para usar todos los elementos finales text.split(/red|green|blue/, -1)y para eliminar todos los elementos vacíos text.split(/red|green|blue/).findAll {it != ""})(ver demostración )
  • - text.split(Regex("red|green|blue"))o, para eliminar elementos en blanco, use text.split(Regex("red|green|blue")).filter{ !it.isBlank() }, vea la demostración
  • - text.split("red|green|blue"), o para mantener todos los elementos vacíos finales, use text.split("red|green|blue", -1)y para eliminar todos los elementos vacíos, use text.split("red|green|blue").filter(_.nonEmpty)(ver demostración )
  • - text.split(/red|green|blue/), para deshacerse de los valores vacíos, use .split(/red|green|blue/).reject(&:empty?)(y para obtener elementos vacíos iniciales y finales, use -1como segundo argumento .split(/red|green|blue/, -1)) (ver demostración )
  • - my @result1 = split /red|green|blue/, $text;, o con todos los elementos vacíos finales my @result2 = split /red|green|blue/, $text, -1;, o sin elementos vacíos, my @result3 = grep { /\S/ } split /red|green|blue/, $text;(ver demostración )
  • - preg_split('~red|green|blue~', $text)o preg_split('~red|green|blue~', $text, -1, PREG_SPLIT_NO_EMPTY)para no generar elementos vacíos (ver demostración )
  • - re.split(r'red|green|blue', text)o, para eliminar elementos vacíos, list(filter(None, re.split(r'red|green|blue', text)))(ver demostración )
  • - Use regexp.MustCompile("red|green|blue").Split(text, -1), y si necesita eliminar elementos vacíos, use este código . Vea la demostración de Go .

NOTA : Si sus patrones contienen grupos de captura , las funciones / métodos de división de expresiones regulares pueden comportarse de manera diferente, también dependiendo de opciones adicionales. A continuación, consulte la documentación del método de división correspondiente.

Wiktor Stribiżew
fuente
0

Todos excepto la palabra "rojo"

var href = '(text-1) (red) (text-3) (text-4) (text-5)';

var test = href.replace(/\((\b(?!red\b)[\s\S]*?)\)/g, testF); 

function testF(match, p1, p2, offset, str_full) {
  p1 = "-"+p1+"-";
  return p1;
}

console.log(test);

Todos excepto la palabra "rojo"

var href = '(text-1) (frede) (text-3) (text-4) (text-5)';

var test = href.replace(/\(([\s\S]*?)\)/g, testF); 

function testF(match, p1, p2, offset, str_full) {
  p1 = p1.replace(/red/g, '');
  p1 = "-"+p1+"-";
  return p1;
}

console.log(test);

Юрий Светлов
fuente