2010-06-23 11 views
5

Hola Tengo una colección de objetos de tipo de nombre y quiero realizar una búsqueda de comodín en él. Por ejemplo, si proporciono un Criterio de búsqueda *ABC, el nombre devuelto debería comenzar con ABC. Si proporciono un Criterio de búsqueda ABC*, el nombre devuelto debe terminar con ABC. Si proporciono un Criterio de búsqueda *ABC*, el nombre devuelto debe contener ABC. Si proporciono un Criterio de búsqueda ?ABC, el segundo, tercer y cuarto caracteres del nombre retornado deberían ser ABC, respectivamente, y el primer carácter puede ser cualquier carácter.búsqueda de LINQ usando caracteres WildCards como *,% ,?

+2

¿Estamos hablando LINQ a objetos aquí, o LINQ to SQL? –

+0

@Samuel: Parece LINQ-to-Objects, ya que él menciona que tiene una "colección [...] de objetos". – ErikHeemskerk

Respuesta

10

Aquí es un método de extensión puede utilizar

public static class EnumerableExtensions 
{ 
    public static IEnumerable<T> MatchesWildcard<T>(this IEnumerable<T> sequence, Func<T,string> expression, string pattern) 
    { 
     var regEx = WildcardToRegex(pattern); 

     return sequence.Where(item => Regex.IsMatch(expression(item), regEx)); 
    } 

    public static string WildcardToRegex(string pattern) 
    { 
     return "^" + Regex.Escape(pattern). 
     Replace("\\*", ".*"). 
     Replace("\\?", ".") + "$"; 
    } 
} 

utilizarlo como sigue:

void Main() 
{ 
    var items = new[] { new MyObj { MyProperty = "ABC123" }, 
         new MyObj { MyProperty = "123ABC" }, 
         new MyObj { MyProperty = "123ABC456" }, 
    }; 

    var matches = items.MatchesWildcard(item => item.MyProperty, "???ABC"); 
} 

public class MyObj 
{ 
    public string MyProperty {get;set;} 
} 

(WildcardToRegex tomado de CodeProject)

+0

Su método Regex (que copió y escribí desde la parte superior de mi cabeza) es mejor que el mío. – ErikHeemskerk

+0

@ErikHeemskerk: ¿por qué molestarse en aprender la sintaxis de RegEx cuando tienes google? :-) –

0

creo que es necesario utilizar .Contains, .StartWith, .EndsWith

3

creo que es necesario Regex.Escape y Regex.IsMatch().

private IEnumerable<Item> FilterList(IEnumerable<Item> list, string query) 
{ 
    string pattern = QueryToRegex(query); 

    return list.Where(i => Regex.IsMatch(i.Name, pattern, RegexOptions.Singleline)); 
} 

private static string QueryToRegex(string query) 
{ 
    return "^" + Regex.Escape(query).Replace("\\*", ".*").Replace("\\?", ".") + "$"; 
} 

Nota: Samuel Jack's answer fue mejor en que su expresión regular era mejor, tan vergonzosamente fijado aquí.

+0

¡Derrotame por 38 segundos, +1! –

+0

Ah, pero de todos modos fue en vano, porque Samuel Jack publicó un método mejor para traducir la expresión comodín a una expresión regular; el mío no funciona correctamente – ErikHeemskerk

0

Este article listas de un método de extensión, que también es compatible con Entity Framework y LINQ-to-entities.

Ejemplo de uso: Código

var searchTerm = "*Inc"; 
var q = db.Customers 
     .WhereLike(c => c.CompanyName, searchTerm, '*') 
     .ToList(); 

Fuente:

using System; 
using System.Collections.Generic; 
using System.Data; 
using System.Data.Objects; 
using System.Data.Objects.DataClasses; 
using System.Linq; 
using System.Linq.Expressions; 
using System.Reflection; 

    public static class LinqExtensions 
    { 
     public static IQueryable<TSource> WhereLike<TSource>(
      this IQueryable<TSource> source, 
      Expression<Func<TSource, string>> valueSelector, 
      string value, 
      char wildcard) 
     { 
      return source.Where(BuildLikeExpression(valueSelector, value, wildcard)); 
     } 

     public static Expression<Func<TElement, bool>> BuildLikeExpression<TElement>(
      Expression<Func<TElement, string>> valueSelector, 
      string value, 
      char wildcard) 
     { 
      if (valueSelector == null) 
       throw new ArgumentNullException("valueSelector"); 

      var method = GetLikeMethod(value, wildcard); 

      value = value.Trim(wildcard); 
      var body = Expression.Call(valueSelector.Body, method, Expression.Constant(value)); 

      var parameter = valueSelector.Parameters.Single(); 
      return Expression.Lambda<Func<TElement, bool>>(body, parameter); 
     } 

     private static MethodInfo GetLikeMethod(string value, char wildcard) 
     { 
      var methodName = "Contains"; 

      var textLength = value.Length; 
      value = value.TrimEnd(wildcard); 
      if (textLength > value.Length) 
      { 
       methodName = "StartsWith"; 
       textLength = value.Length; 
      } 

      value = value.TrimStart(wildcard); 
      if (textLength > value.Length) 
      { 
       methodName = (methodName == "StartsWith") ? "Contains" : "EndsWith"; 
       textLength = value.Length; 
      } 

      var stringType = typeof(string); 
      return stringType.GetMethod(methodName, new Type[] { stringType }); 
     } 
    } 
Cuestiones relacionadas