像LINQ to Objects中的运算符一样

Ant*_*nov 12 c# linq-to-objects sql-like

我试图LIKE在LINQ to Objects中模拟运算符.这是我的代码:

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;
Run Code Online (Sandbox Code Playgroud)

它没有得到我的结果,因为System.Data.Linq.SqlClient.SqlMethods.Like它只是为了翻译成SQL.

LIKE在LINQ to Objects世界中是否存在类似于sql 运算符的东西?

jvs*_*ech 18

我不知道哪一个很容易存在,但如果你熟悉正则表达式,你可以编写自己的:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

然后在你的代码中:

string pattern = ".*ine.*e";
var res = from i in list
    where i.Like(pattern)
    select i;
Run Code Online (Sandbox Code Playgroud)


dka*_*man 7

此代码段将模仿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);
}
Run Code Online (Sandbox Code Playgroud)

一个粗糙的扩展方法,可以像IEnumerable<T>.Where方法一样工作:

public static IEnumerable<T> Like<T>(this IEnumerable<T> source, Func<T, string> selector, string pattern)
{
   return source.Where(t => IsSqlLikeMatch(selector(t), pattern));
}
Run Code Online (Sandbox Code Playgroud)

这反过来允许您格式化您的语句,如下所示:

string pattern = "%ine%e";
var res = list.Like(s => s, pattern);
Run Code Online (Sandbox Code Playgroud)

编辑 一个改进的实现,任何人都应该偶然发现并想要使用此代码.它为每个项目转换并编译一次正则表达式,并且从LIKE到regex的转换有一些错误.

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();
    }
}
Run Code Online (Sandbox Code Playgroud)


Øyv*_*hen 5

您必须使用Regex作为模式,然后使用扩展方法Where迭代并查找匹配项.

所以你的代码应该像这样结束:

string pattern = @".*ine.*e$";

var res = list.Where( e => Regex.IsMatch( e, pattern));
Run Code Online (Sandbox Code Playgroud)

如果您不熟悉Regex,请阅读:

前0个或多个字符(.*)后跟ine (ine)然后是0个或更多个字符(.*)然后是e (e),e应该是字符串的结尾($)