Regex: quiero esto Y eso Y eso … en cualquier orden

Ni siquiera estoy seguro de si esto es posible o no, pero esto es lo que me gustaría.

String: "NS306 FEBRUARY 20078/9/201013B1-9-1Low31 AUGUST 19870" 

Tengo un cuadro de texto donde escribo los parámetros de búsqueda y están delimitados por espacios. Debido a esto, quiero devolver una coincidencia: string1 está en la cadena y luego string2 está en la cadena, O string2 está en la cadena y luego string1 está en la cadena. No me importa en qué orden están las cuerdas, pero TODAS (tendrán algo más de 2) tienen que estar en la cuerda.

Entonces, por ejemplo, en la cadena provista, me gustaría:

 "FEB Low" 

o

 "Low FEB" 

… para volver como un partido.

Soy REALMENTE nuevo en Regex, solo leo algunos tutoriales aquí, pero eso fue hace un tiempo y necesito hacerlo hoy. El lunes comienzo un nuevo proyecto que es mucho más importante y no se puede distraer con este problema. ¿Hay alguna forma de hacer esto con expresiones regulares, o tengo que iterar a través de cada parte del filtro de búsqueda y permuta la orden? Cualquier y toda ayuda es extremadamente apreciada. Gracias.

ACTUALIZACIÓN: La razón por la que no quiero iterar a través de un bucle y estoy buscando el mejor rendimiento es porque lamentablemente, la tabla de datos que estoy usando llama a esta función en cada pulsación de tecla, y no quiero que se empantane .

ACTUALIZACIÓN: Gracias a todos por su ayuda, fue muy apreciada.

ACTUALIZACIÓN DEL CÓDIGO:

En definitiva, esto es con lo que fui.

 string sSearch = nvc["sSearch"].ToString().Replace(" ", ")(?=.*"); if (sSearch != null && sSearch != "") { Regex r = new Regex("^(?=.*" + sSearch + ").*$", RegexOptions.IgnoreCase); _AdminList = _AdminList.Where( delegate(IPB ipb) { //Concatenated all elements of IPB into a string bool returnValue = r.IsMatch(strTest); //strTest is the concatenated string return returnValue; }).ToList(); } } 

La clase IPB tiene X cantidad de elementos y en ninguna tabla del sitio en el que estoy trabajando son las columnas en el mismo orden. Por lo tanto, necesitaba buscar cualquier orden y no quería tener que escribir mucho código para hacerlo. Hubo otras buenas ideas aquí, pero sé que a mi jefe realmente le gusta Regex (las predica) y por lo tanto, pensé que sería mejor si lo hiciera por el momento. Si por alguna razón el rendimiento del sitio se desliza (sitio de intranet), entonces intentaré de otra manera. Gracias a todos.

Puede usar (?=…) búsqueda anticipada positiva ; afirma que un patrón dado puede ser igualado. Deberías anclar al principio de la cuerda, y uno por uno, en cualquier orden, buscar una coincidencia de cada uno de tus patrones.

Se verá algo como esto:

 ^(?=.*one)(?=.*two)(?=.*three).*$ 

Esto coincidirá con una cadena que contiene "one" , "two" , "three" , en cualquier orden ( como se ve en rubular.com ).

Dependiendo del contexto, puede anclar en \A y \Z , y usar el modo de línea única para que el punto coincida con todo.

Esta no es la solución más eficiente para el problema. La mejor solución sería analizar las palabras en su entrada y ponerlas en una representación de conjunto eficiente, etc.

Preguntas relacionadas

  • ¿Cómo funciona la expresión regular (?<=#)[^#]+(?=#) ?

Ejemplo más práctico: validación de contraseñas

Digamos que queremos nuestra contraseña para:

  • Contiene entre 8 y 15 caracteres
  • Debe contener una letra mayúscula
  • Debe contener una letra minúscula
  • Debe contener un dígito
  • Debe contener uno de los símbolos especiales

Entonces podemos escribir una expresión regular como esta:

 ^(?=.{8,15}$)(?=.*[AZ])(?=.*[az])(?=.*[0-9])(?=.*[!@#$%^&*]).*$ \__________/\_________/\_________/\_________/\______________/ length upper lower digit symbol 

¿Por qué no simplemente hacer una simple verificación del texto ya que el orden no importa?

 string test = "NS306 FEBRUARY 20078/9/201013B1-9-1Low31 AUGUST 19870"; test = test.ToUpper(); bool match = ((test.IndexOf("FEB") >= 0) && (test.IndexOf("LOW") >= 0)); 

¿Lo necesitas para usar regex?

Creo que lo más conveniente para hoy será string.Split(' ') los términos de búsqueda y luego itere sobre los resultados que confirman que sourceString.Contains(searchTerm)

 var source = @"NS306 FEBRUARY 20078/9/201013B1-9-1Low31 AUGUST 19870".ToLowerInvariant(); var search = "FEB Low"; var terms = search.Split(' '); bool all_match = !terms.Any(term => !(source.Contains(term.ToLowerInvariant()))); 

Tenga en cuenta que usamos Any() para configurar un cortocircuito, por lo tanto, si el primer término no coincide, omitiremos verificar el segundo, el tercero, y así sucesivamente.


Este no es un gran caso de uso para RegEx. La manipulación de cadena necesaria para tomar un número arbitrario de cadenas de búsqueda y convertirlo en un patrón casi seguro niega el beneficio de rendimiento de igualar el patrón con el motor de RegEx, aunque esto puede variar según con qué coincida.

Ha indicado en algunos comentarios que desea evitar un bucle, pero RegEx no es una solución de una sola pasada. No es difícil crear búsquedas terriblemente improductivas que se repiten y se repiten carácter por carácter, como el infame retroceso catastrófico , donde una coincidencia muy simple requiere miles de pasos para devolver el resultado false .

 var text = @"NS306Low FEBRUARY 2FEB0078/9/201013B1-9-1Low31 AUGUST 19870"; var matches = Regex.Matches(text, @"(FEB)|(Low)"); foreach (Match match in matches) { Console.WriteLine(match.Value); } Output: Low FEB FEB Low 

Debería comenzar.

La respuesta de @polygenelubricants es completa y perfecta, pero tuve un caso en el que quería hacer coincidir una fecha y otra cosa, por ejemplo, un número de 10 dígitos para que la búsqueda no coincida y no puedo hacerlo solo con lookaheads, así que usé grupos nombrados :

(?:.*(?P<1>[0-9]{10}).*(?P<2>2[0-9]{3}-(?:0?[0-9]|1[0-2])-(?:[0-2]?[0-9]|3[0-1])).*)+

y de esta manera, el número siempre es el grupo 1 y la fecha siempre es el grupo 2. Por supuesto, tiene algunos defectos, pero fue muy útil para mí y pensé que debería compartirlo. (mira https://www.debuggex.com/r/YULCcpn8XtysHfmE )

No tiene que probar cada permutación, simplemente divida su búsqueda en varias partes “FEB” y “Bajo” y asegúrese de que cada parte coincida. Eso será mucho más fácil que tratar de encontrar una expresión regular que coincida con todo el asunto de una vez (lo que estoy seguro es teóricamente posible, pero probablemente no sea práctico en realidad).

Use string.Split (). Devolverá una matriz de subcadenas que están delimitadas por una cadena / char especificada. El código se verá algo como esto.

int maximumSize = 100;
string myString = "NS306 FEBRUARY 20078/9/201013B1-9-1Low31 AUGUST 19870";
string[] individualString = myString.Split(' ', maximumSize);

Para más información http://msdn.microsoft.com/en-us/library/system.string.split.aspx

Editar: si realmente desea usar expresiones regulares, este patrón funcionará. [^ ]* Y solo usará Regex.Matches (); El código será algo como esto:

string myString = "NS306 FEBRUARY 20078/9/201013B1-9-1Low31 AUGUST 19870";
string pattern = "[^ ]*"; Regex rgx = new Regex(pattern);
foreach(Match match in reg.Matches(s))
{
//do stuff with match.value
}