我有两个字符串列表,第一个列表是电子邮件列表,第二个列表是可能包含通配符*和/或?的可能匹配列表。 (*用于延迟匹配,?用于单字符macthing)
第一个列表示例:
email1
email2
etc
第二个名单示例:
*@gmail.com
bob@*.com
tony??@*.com
我想返回一个列表,该列表使用第二个列表从第一个列表中删除匹配。
我最初看过Except方法,因为它似乎是一种非常高效的迭代和快速比较两个列表的方法。这很好用。然后我尝试将RegEx集成到混合中,然后事情变得更加复杂......
我在Equals重载中使用以下内容创建了一个自定义比较器: return(new Regex(x,RegexOptions.IgnoreCase))。IsMatch(y);
但这似乎没有提供我预期的结果!有没有更简单的方法来克服这种情况?
答案 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}调用Where
或All
来调整匹配的条件。
答案 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;}
}
重要细节
Info
是包含要过滤的电子邮件列表的类,在您的情况下为FirstList emailPatterns
是用于映射的正则表达式模式,我已经从@Slai的答案中复制了相同的内容,因为我对Regex不是很确定finalResult
是最终答案,使用我使用的数据时这是正确的