2010-06-23 5 views
5

Salut J'ai une collection d'objets de type nom et je veux y effectuer une recherche par caractère générique. Par exemple, si je fournis un critère de recherche *ABC, le nom renvoyé doit commencer par ABC. Si je fournis un critère de recherche ABC*, le nom retourné doit se terminer par ABC. Si je fournis un critère de recherche *ABC*, le nom renvoyé doit contenir ABC. Si je fournis un critère de recherche ?ABC, les deuxième, troisième et quatrième caractères renvoyés doivent être respectivement ABC et le premier caractère peut être n'importe quel caractère.La recherche LINQ utilisant le caractère WildCards comme *,% ,?

+2

que nous parlons LINQ à des objets ici ou LINQ to SQL? –

+0

@Samuel: On dirait que LINQ-to-Objects, comme il le mentionne, a une 'collection d'objets'. – ErikHeemskerk

Répondre

10

est ici une méthode d'extension, vous pouvez utiliser

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("\\?", ".") + "$"; 
    } 
} 

utiliser comme suit:

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 pris de CodeProject)

+0

Votre méthode Regex (que vous avez copiée et j'ai tapée du haut de ma tête) est meilleure que la mienne. – ErikHeemskerk

+0

@ErikHeemskerk - Pourquoi apprendre la syntaxe RegEx quand vous avez google? :-) –

0

Je pense que vous devez utiliser .Contains, .StartWith, .EndsWith

3

Je pense que vous avez besoin Regex.Escape et 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("\\?", ".") + "$"; 
} 

Note: Samuel Jack's answer était mieux que son Regex valait mieux, si honteusement fixé ici.

+0

Battez-moi de 38 secondes, +1! –

+0

Ah, mais c'était en vain parce que Samuel Jack a posté une meilleure méthode pour traduire l'expression générique en une regex; le mien ne fonctionne pas correctement. – ErikHeemskerk

0

Cette article listes une méthode d'extension qui est également compatible avec Entity Framework et LINQ-to-entities.

Exemple d'utilisation:

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

code source:

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 }); 
     } 
    } 
Questions connexes