正则搜索如何匹配所有单词?SQL多列(含姓名组合)搜索实现
解决姓名组合搜索的问题
现有代码的核心问题是:当输入「Walter White」这类带空格的组合字符串时,会用整个字符串去匹配Name或Surname列,而这两列单独存储名和姓,自然匹配失败。要实现姓名组合搜索,需要先拆分搜索关键词,再验证这些关键词是否分布在Name和Surname中。
具体修改步骤
- 拆分搜索关键词:将用户输入的字符串按空格分割,过滤空字符串,得到关键词列表。
- 新增姓名组合匹配逻辑:如果关键词数量≥2,检查这些关键词是否分别出现在Name和Surname中(支持不区分顺序或严格顺序匹配,按需调整)。
- 优化去重逻辑:用
HashSet存储已匹配的ID,替代原代码中效率低下的results.Any判断。
修改后的代码示例
var searchKeywords = search.Split(new[] {' '}, StringSplitOptions.RemoveEmptyEntries); var pattern = @$"({search})"; var matchedIds = new HashSet<int>(); // 用HashSet提升去重检查效率 var results = new List<Member>(); foreach (var member in context.Members.Where(x => x.IsActive)) { if (matchedIds.Contains(member.Id)) continue; bool isMatched = false; // 原有单字段匹配逻辑 if (!string.IsNullOrEmpty(member.Name) && Regex.IsMatch(member.Name, pattern, RegexOptions.IgnoreCase)) { isMatched = true; } else if (!string.IsNullOrEmpty(member.Surname) && Regex.IsMatch(member.Surname, pattern, RegexOptions.IgnoreCase)) { isMatched = true; } else if (!string.IsNullOrEmpty(member.Email) && Regex.IsMatch(member.Email, pattern, RegexOptions.IgnoreCase)) { isMatched = true; } else if (!string.IsNullOrEmpty(member.IdNumber) && Regex.IsMatch(member.IdNumber, pattern, RegexOptions.IgnoreCase)) { isMatched = true; } // 新增姓名组合匹配逻辑(支持不区分关键词顺序) else if (searchKeywords.Length >= 2) { var nameParts = new[] { member.Name?.Trim(), member.Surname?.Trim() }.Where(s => !string.IsNullOrEmpty(s)); isMatched = searchKeywords.All(keyword => nameParts.Any(part => Regex.IsMatch(part, $@"({keyword})", RegexOptions.IgnoreCase))); } if (isMatched) { results.Add(member); matchedIds.Add(member.Id); } }
逻辑说明
- 关键词拆分:处理多空格、首尾空格的情况,确保得到有效关键词。
- HashSet去重:
HashSet.Contains是O(1)操作,远快于原代码的遍历检查。 - 姓名组合匹配:默认支持任意顺序的关键词匹配(比如「White Walter」也能找到Name=Walter、Surname=White的用户)。如果需要严格按名+姓的顺序匹配,可替换为以下逻辑:
else if (searchKeywords.Length >= 2) { bool matchNameFirst = !string.IsNullOrEmpty(member.Name) && Regex.IsMatch(member.Name, $@"({searchKeywords[0]})", RegexOptions.IgnoreCase) && !string.IsNullOrEmpty(member.Surname) && Regex.IsMatch(member.Surname, $@"({searchKeywords[1]})", RegexOptions.IgnoreCase); bool matchSurnameFirst = !string.IsNullOrEmpty(member.Name) && Regex.IsMatch(member.Name, $@"({searchKeywords[1]})", RegexOptions.IgnoreCase) && !string.IsNullOrEmpty(member.Surname) && Regex.IsMatch(member.Surname, $@"({searchKeywords[0]})", RegexOptions.IgnoreCase); isMatched = matchNameFirst || matchSurnameFirst; }
额外优化建议
如果数据库数据量较大,当前内存循环匹配的方式效率较低,建议将逻辑转换为EF Core可解析的LINQ表达式,让数据库直接执行查询,避免加载所有Active成员到内存中。
内容的提问来源于stack exchange,提问作者Logany-hi
相关产品推荐
相关产品推荐

