像LINQ中的对象运算符

| 我正在尝试在LINQ to Objects中模拟
LIKE
运算符。这是我的代码:
List<string> list = new List<string>();
list.Add(\"line one\");
list.Add(\"line two\");
list.Add(\"line three\");
list.Add(\"line four\");
list.Add(\"line five\");
list.Add(\"line six\");
list.Add(\"line seven\");
list.Add(\"line eight\");
list.Add(\"line nine\");
list.Add(\"line ten\");

string pattern = \"%ine%e\";

var res = from i in list
            where System.Data.Linq.SqlClient.SqlMethods.Like(i, pattern)
              select i;
由于
System.Data.Linq.SqlClient.SqlMethods.Like
仅用于转换为SQL,因此没有得到我的结果。 LINQ to Objects世界中是否存在类似于sql
LIKE
运算符的东西?     
已邀请:
我不知道一个现成的,但是如果您熟悉正则表达式,则可以编写自己的正则表达式:
using System;
using System.Text.RegularExpressions;

public static class MyExtensions
{
    public static bool Like(this string s, string pattern, RegexOptions options = RegexOptions.IgnoreCase)
    {
        return Regex.IsMatch(s, pattern, options);
    }
}
然后在您的代码中:
string pattern = \".*ine.*e\";
var res = from i in list
    where i.Like(pattern)
    select i;
    
此代码段将模仿Sql LIKE的行为和语法。您可以将其包装为自己的lambda或扩展方法,以在Linq语句中使用:
public static bool IsSqlLikeMatch(string input, string pattern)
{
   /* Turn \"off\" all regular expression related syntax in
    * the pattern string. */
   pattern = Regex.Escape(pattern);

   /* Replace the SQL LIKE wildcard metacharacters with the
    * equivalent regular expression metacharacters. */
   pattern = pattern.Replace(\"%\", \".*?\").Replace(\"_\", \".\");

   /* The previous call to Regex.Escape actually turned off
    * too many metacharacters, i.e. those which are recognized by
    * both the regular expression engine and the SQL LIKE
    * statement ([...] and [^...]). Those metacharacters have
    * to be manually unescaped here. */
   pattern = pattern.Replace(@\"\\[\", \"[\").Replace(@\"\\]\", \"]\").Replace(@\"\\^\", \"^\");

   return Regex.IsMatch(input, pattern, RegexOptions.IgnoreCase);
}
类似于extension7ѭ方法的粗糙扩展方法:
public static IEnumerable<T> Like<T>(this IEnumerable<T> source, Func<T, string> selector, string pattern)
{
   return source.Where(t => IsSqlLikeMatch(selector(t), pattern));
}
反过来,这将使您可以像这样设置语句的格式:
string pattern = \"%ine%e\";
var res = list.Like(s => s, pattern);
编辑 一个改进的实现,如果任何人偶然发现并想使用此代码。它为每个项目一次转换和编译正则表达式,而从LIKE到上述正则表达式的转换存在一些错误。
public static class LikeExtension
{
    public static IEnumerable<T> Like<T>(this IEnumerable<T> source, Func<T, string> selector, string pattern)
    {
        var regex = new Regex(ConvertLikeToRegex(pattern), RegexOptions.IgnoreCase);
        return source.Where(t => IsRegexMatch(selector(t), regex));
    }

    static bool IsRegexMatch(string input, Regex regex)
    {
        if (input == null)
            return false;

        return regex.IsMatch(input);
    }

    static string ConvertLikeToRegex(string pattern)
    {
        StringBuilder builder = new StringBuilder();
        // Turn \"off\" all regular expression related syntax in the pattern string
        // and add regex begining of and end of line tokens so \'%abc\' and \'abc%\' work as expected
        builder.Append(\"^\").Append(Regex.Escape(pattern)).Append(\"$\");

        /* Replace the SQL LIKE wildcard metacharacters with the
        * equivalent regular expression metacharacters. */
        builder.Replace(\"%\", \".*\").Replace(\"_\", \".\");

        /* The previous call to Regex.Escape actually turned off
        * too many metacharacters, i.e. those which are recognized by
        * both the regular expression engine and the SQL LIKE
        * statement ([...] and [^...]). Those metacharacters have
        * to be manually unescaped here. */
        builder.Replace(@\"\\[\", \"[\").Replace(@\"\\]\", \"]\").Replace(@\"\\^\", \"^\");

        // put SQL LIKE wildcard literals back
        builder.Replace(\"[.*]\", \"[%]\").Replace(\"[.]\", \"[_]\");

        return builder.ToString();
    }
}
    
您必须使用正则表达式作为模式,然后使用扩展方法
Where
进行迭代并找到匹配项。 因此,您的代码应最终如下所示:
string pattern = @\".*ine.*e$\";

var res = list.Where( e => Regex.IsMatch( e, pattern));
如果您不熟悉Regex,则显示为: 前0个或多个字符(。*),然后是ine(ine),然后是0个或多个字符(。*),然后是e(e),e应该是字符串($)的结尾     
1.使用String.StartsWith或String.Endswith 编写以下查询:
var query = from c in ctx.Customers

            where c.City.StartsWith(\"Lo\")

            select c;

will generate this SQL statement:
SELECT CustomerID, CompanyName, ...
FROM    dbo.Customers
WHERE  City LIKE [Lo%]
这正是我们想要的。 String.EndsWith也是如此。 但是,我们要查询城市名称为\“ L_n%\”这样的客户吗? (以大写字母\'L \'开头,而不是某些字符,\'n \'以及其他名称开头)。使用查询
var query = from c in ctx.Customers

            where c.City.StartsWith(\"L\") && c.City.Contains(\"n\")

            select c;

generates the statement:
SELECT CustomerID, CompanyName, ...
FROM    dbo.Customers
WHERE  City LIKE [L%]
AND      City LIKE [%n%]
这不完全是我们想要的,也更加复杂。 2.使用SqlMethods.Like方法 深入研究“ 15”命名空间,我发现了一个名为SqlMethods的辅助类,在此类情况下可能非常有用。 SqlMethods有一个名为Like的方法,可以在Linq to SQL查询中使用:
var query = from c in ctx.Customers

            where SqlMethods.Like(c.City, \"L_n%\")

            select c;
此方法获取要检查的字符串表达式(在此示例中为客户所在的城市),并以与您在SQL中编写LIKE子句相同的方式提供要测试的模式。 使用上面的查询生成所需的SQL语句:
SELECT CustomerID, CompanyName, ...
FROM    dbo.Customers
WHERE  City LIKE [L_n%]
来源:http://blogs.microsoft.co.il/blogs/bursteg/archive/2007/10/16/linq-to-sql-like-operator.aspx     
我不知道它是否存在,但这是使用我制作的Knuth-Morris-Pratt算法的扩展方法的实现。
public static IEnumerable<T> Like<T>(this IEnumerable<T> lista, Func<T, string> type, string pattern)
            {

                int[] pf = prefixFunction(pattern);

                foreach (T e in lista)
                {
                    if (patternKMP(pattern, type(e), pf))
                        yield return e;
                }

            }

            private static int[] prefixFunction(string p)
            {


                int[] pf = new int[p.Length];
                int k = pf[0] = -1;


                for (int i = 1; i < p.Length; i++)
                {
                    while (k > -1 && p[k + 1] != p[i])
                        k = pf[k];

                    pf[i] = (p[k + 1] == p[i]) ? ++k : k;
                }
                return pf;

            }

            private static bool patternKMP(string p, string t, int[] pf)
            {

                for (int i = 0, k = -1; i < t.Length; i++)
                {

                    while (k > -1 && p[k + 1] != t[i])
                        k = pf[k];

                    if (p[k + 1] == t[i])
                        k++;

                    if (k == p.Length - 1)
                        return true;    
                }

                return false;

            }
    

要回复问题请先登录注册