LINQ除了C#中的RegEx

时间:2017-03-27 10:45:34

标签: c# linq

我有两个字符串列表,第一个列表是电子邮件列表,第二个列表是可能包含通配符*和/或?的可能匹配列表。 (*用于延迟匹配,?用于单字符macthing)

第一个列表示例:

email1
email2
etc

第二个名单示例:

*@gmail.com
bob@*.com
tony??@*.com

我想返回一个列表,该列表使用第二个列表从第一个列表中删除匹配。

我最初看过Except方法,因为它似乎是一种非常高效的迭代和快速比较两个列表的方法。这很好用。然后我尝试将RegEx集成到混合中,然后事情变得更加复杂......

我在Equals重载中使用以下内容创建了一个自定义比较器: return(new Regex(x,RegexOptions.IgnoreCase))。IsMatch(y);

但这似乎没有提供我预期的结果!有没有更简单的方法来克服这种情况?

4 个答案:

答案 0 :(得分:2)

试试这个:

var filtered = list1.Where(y => list2.Any(x => new Regex(x, RegexOptions.IgnoreCase).IsMatch(y));

但是,我认为它不会特别高效,所以如果您要检查一个大清单,我建议您查看其他方法。

这可能更高效:

var list1 = new List<string>();
var list2 = new List<string>();

var regex = new Regex(string.Join("|", list2.Select(l => string.Concat("(", l, ")")).ToArray()), RegexOptions.IgnoreCase);
var filtered = list1.Where(l => regex.IsMatch(l));

答案 1 :(得分:2)

您不能在基于等式的场景中使用a.IsMatch(b),因为它不满足相等的基本要求(对称性)。因为它需要两侧不同类型的物品,它也不是传递性的,也不是反身的。

Except方法快的原因是它可以使用基于散列的匹配。遗憾的是,基于正则表达式的匹配是不可能的,因此您需要处理O(n * r)解决方案(n是项目数,r是正则表达式的数量),即{{1}调用WhereAll来调整匹配的条件。

答案 2 :(得分:2)

不需要LINQ:

var list1 = new List<string> { "email1", "email2" };
string[] list2 = { "*@gmail.com", "bob@*.com", "tony??@*.com" };

var pattern = "^(" + Regex.Escape(string.Join("|", list2)).Replace("\\|", "|").Replace("\\?", ".?").Replace("\\*", ".*") + ")$"; 
var regEx = new Regex(pattern, RegexOptions.Compiled | RegexOptions.IgnoreCase);

list1.RemoveAll(regEx.IsMatch);

答案 3 :(得分:2)

对于大量的记录,表达式树将是实现它的最快方法,请检查以下代码:

void Main()
{
    // Create EXpression parameter for the Info Type
    var parameterType = Expression.Parameter(typeof(Info), "obj");

    // Access the Email member for the Type Info in the Expression type
    var memmberExpressionProperty = Expression.Property(parameterType, "Email");

    // Regex Patterns
    HashSet<string> emailPatterns = new HashSet<string>
    {    
      @"^(.*@gmail\.com|bob@.*\.com|tony.?.?@.*\.com)$"
    };

    // Wrapping and Calling the Extension method for Regex match
    MethodInfo filtersMethodInfo = typeof(StringExtensions).GetMethod("RegexMatch", new[] { typeof(string), typeof(HashSet<string>) });

    // Create Constant Expression and supply the Email Patterns Hashset
    ConstantExpression  filtersConstantExpression = Expression.Constant(emailPatterns, typeof(HashSet<string>));

    // Create Final Expression - MethodCall Expression
    var finalExpression = Expression.Call(null, filtersMethodInfo, memmberExpressionProperty, filtersConstantExpression);

    // Compile the EXpression Lambda
    var resultFunc = Expression.Lambda<Func<Info, bool>>(finalExpression, parameterType).Compile();

    // Email Data for filtering
    List<Info> EmailInfo = new List<Info>()
   {
     new Info {Email="abcd@gmail.com"},
     new Info {Email="abcc@gmail2.com"},
     new Info {Email="vbhg@guuumail.com"},
     new Info {Email="kkkk@gmail.com"},
     new Info {Email="jjjj@gqqqmail.com"}
};

    var finalResult = EmailInfo.Where(obj => resultFunc(obj));
}

public static class StringExtensions
{
    public static bool RegexMatch(this string source, HashSet<string> patternHashset)
    {
        return source != null && patternHashset.Any(pattern => Regex.Match(source, pattern, RegexOptions.IgnoreCase).Success);
    }
}

public class Info
{
    public string Email { get; set;}
}

重要细节

  1. Info是包含要过滤的电子邮件列表的类,在您的情况下为FirstList
  2. emailPatterns是用于映射的正则表达式模式,我已经从@Slai的答案中复制了相同的内容,因为我对Regex不是很确定
  3. 我们创建一个RegexMatch作为字符串Extension,它与所提供的Hashset中的所有模式匹配,并在任何匹配中提供真实结果
  4. 编译表达式树,finalResult是最终答案,使用我使用的数据时这是正确的