numeros - regex performance c#
Regex: quiero esto Y aquello Y aquello... en cualquier orden (7)
¿Por qué no hacer una simple comprobació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?
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 si cadena1 está en la cadena y luego cadena2 está en la cadena, O cadena2 está en la cadena y luego cadena1 está en la cadena. No me importa en qué orden están las cuerdas, pero TODAS (algunas veces más de 2) tienen que estar en la cadena.
Así, por ejemplo, en la cadena provista querría:
"FEB Low"
o
"Low FEB"
... para volver como un partido.
Soy REALMENTE nuevo en Regex, solo leí algunos tutoriales here pero eso fue hace un tiempo y necesito terminar esto hoy. El lunes empiezo 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 recorrer cada parte del filtro de búsqueda y permutar el orden? Cualquier ayuda es muy apreciada. Gracias.
ACTUALIZACIÓN: la razón por la que no quiero recorrer un bucle y estoy buscando el mejor rendimiento es porque desafortunadamente, la tabla de datos que estoy usando llama a esta función con cada pulsación de tecla, y no quiero que se atasque .
ACTUALIZACIÓN: Gracias a todos por su ayuda, fue muy apreciado.
ACTUALIZACIÓN DEL CÓDIGO:
En última instancia, 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<IPB>(
delegate(IPB ipb)
{
//Concatenated all elements of IPB into a string
bool returnValue = r.IsMatch(strTest); //strTest is the concatenated string
return returnValue;
}).ToList<IPB>();
}
}
La clase IPB tiene X número de elementos y en ninguna tabla en todo el sitio en el que estoy trabajando están las columnas en el mismo orden. Por lo tanto, necesitaba realizar una búsqueda de órdenes y no quería tener que escribir muchos códigos para hacerlo. Había 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 ahora. Si, por alguna razón, el rendimiento del sitio se resbala (sitio de intranet), lo intentaré de otra manera. Gracias a todos.
Creo que lo más conveniente para el día de hoy será string.Split('' '')
los términos de búsqueda y luego iterar sobre los resultados confirmando 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 que si el primer término no coincide, omitimos la comprobación del segundo, tercero, etc.
Este no es un gran caso de uso para RegEx. La manipulación de la cadena necesaria para tomar un número arbitrario de cadenas de búsqueda y convertirla en un patrón es casi seguro que niega la ventaja de rendimiento de hacer coincidir el patrón con el motor RegEx, aunque esto puede variar según el tipo de comparación.
En algunos comentarios, ha indicado que desea evitar un bucle, pero RegEx no es una solución de un solo paso. No es difícil crear búsquedas espantosas sin rendimiento que se mueven paso a paso, carácter por personaje, como el infame retroceso catastrófico , donde una coincidencia muy simple requiere miles de pasos para devolver el resultado false
.
La respuesta de @polygenelubricants es completa y perfecta, pero tuve un caso en el que quería hacer coincidir una fecha y algo más, por ejemplo, un número de 10 dígitos, así que el lookahead no coincide y no puedo hacerlo solo con lookaheads, así que usé grupos con nombre :
(?:.*(?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 algunas fallas, pero fue muy útil para mí y pensé que debía compartirlo. (eche un vistazo a https://www.debuggex.com/r/YULCcpn8XtysHfmE )
No tiene que probar cada permutación, simplemente divida su búsqueda en varias partes "FEB" y "Baja" y asegúrese de que cada parte coincida. Eso será mucho más fácil que tratar de crear una expresión regular que coincida con todo en una sola vez (lo que estoy seguro es teóricamente posible, pero probablemente no sea práctico en la realidad).
Puedes usar (?=…)
lookahead positivo ; afirma que un patrón dado puede ser emparejado. Se anclará al principio de la cadena, y uno por uno, en cualquier orden, buscará una coincidencia de cada uno de sus 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, es posible que desee anchor 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 al problema. La mejor solución sería analizar las palabras en su entrada y colocarlas en una representación de conjunto eficiente, etc.
Preguntas relacionadas
Ejemplo más práctico: validación de contraseña
Digamos que queremos que nuestra contraseña:
- 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}$)(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])(?=.*[!@#$%^&*]).*$
/__________//_________//_________//_________//______________/
length upper lower digit symbol
Utilice string.Split (). Devolverá una matriz de subtrings que se delimitará 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 obtener más información, http://msdn.microsoft.com/en-us/library/system.string.split.aspx
Edición: si realmente desea utilizar expresiones regulares, este patrón funcionará. [^ ]*
Y solo usarás 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
}
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 empezar.