LINQ搜索使用像*,%,?的WildCards字符

时间:2010-06-23 13:55:51

标签: c#

您好我有一个名称类型对象的集合,我想对它进行通配符搜索。例如,如果我提供搜索条件*ABC,则返回的名称应以ABC开头。如果我提供搜索条件ABC*,则返回的名称应以ABC结尾。如果我提供搜索条件*ABC*,则返回的名称应包含ABC。如果我提供搜索条件?ABC,则返回的名称的第二个,第三个和第四个字符应分别为ABC,第一个字符可以是任何字符。

4 个答案:

答案 0 :(得分:10)

这是您可能使用的扩展方法

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

按如下方式使用:

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取自CodeProject

答案 1 :(得分:3)

我认为你需要Regex.Escape和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("\\?", ".") + "$";
}

注意:Samuel Jack's answer更好,因为他的正则表达式更好,所以在这里可耻地修复它。

答案 2 :(得分:0)

我认为你需要使用.Contains,.StartWith,.EndsWith

答案 3 :(得分:0)

article列出了一个与Entity Framework和LINQ-to-entities兼容的扩展方法。

使用示例:

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

源代码:

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