using System.Text.RegularExpressions;
namespace Dpz.Core.Service.Mediator.Features.Search;
/// <summary>
/// 统一分析搜索关键字,兼容中英文输入并生成查询词与高亮词。
/// </summary>
public static partial class SearchKeywordAnalyzer
{
private const int MaxQueryTerms = 8;
private const int MaxHighlightTerms = 24;
/// <summary>
/// 分析用户输入,生成规范化关键字、查询词和高亮词。
/// </summary>
public static SearchKeywordAnalysis Analyze(string? keyword)
{
var normalizedKeyword = Normalize(keyword);
if (string.IsNullOrWhiteSpace(normalizedKeyword))
{
return SearchKeywordAnalysis.Empty;
}
var queryTerms = new List<string>();
var highlightTerms = new List<string>();
var rawTokens = TokenRegex()
.Matches(normalizedKeyword)
.Select(x => x.Value)
.Where(x => !string.IsNullOrWhiteSpace(x))
.Distinct(StringComparer.OrdinalIgnoreCase)
.ToList();
foreach (var token in rawTokens)
{
if (ContainsCjk(token))
{
AddTerm(queryTerms, token);
AddTerm(highlightTerms, token);
foreach (var gram in BuildNGrams(token, 2))
{
AddTerm(queryTerms, gram);
AddTerm(highlightTerms, gram);
}
continue;
}
AddTerm(queryTerms, token.ToLowerInvariant());
AddTerm(highlightTerms, token);
}
if (queryTerms.Count == 0)
{
AddTerm(queryTerms, normalizedKeyword);
AddTerm(highlightTerms, normalizedKeyword);
}
var sortedQueryTerms = queryTerms
.Distinct(StringComparer.OrdinalIgnoreCase)
.OrderByDescending(x => x.Length)
.ThenBy(x => x, StringComparer.OrdinalIgnoreCase)
.Take(MaxQueryTerms)
.ToList();
var sortedHighlightTerms = highlightTerms
.Distinct(StringComparer.OrdinalIgnoreCase)
.OrderByDescending(x => x.Length)
.ThenBy(x => x, StringComparer.OrdinalIgnoreCase)
.Take(MaxHighlightTerms)
.ToList();
return new SearchKeywordAnalysis(normalizedKeyword, sortedQueryTerms, sortedHighlightTerms);
}
/// <summary>
/// 将关键词转成正则并按长度降序,避免短词吞噬长词。
/// </summary>
public static string BuildRegexPattern(IEnumerable<string> terms)
{
var escapedTerms = terms
.Where(x => !string.IsNullOrWhiteSpace(x))
.Select(Regex.Escape)
.Distinct(StringComparer.OrdinalIgnoreCase)
.OrderByDescending(x => x.Length)
.ToList();
return escapedTerms.Count == 0 ? string.Empty : string.Join('|', escapedTerms);
}
private static string Normalize(string? keyword)
{
if (string.IsNullOrWhiteSpace(keyword))
{
return string.Empty;
}
return string.Join(
' ',
keyword.Split([' ', '\t', '\r', '\n'], StringSplitOptions.RemoveEmptyEntries)
);
}
private static bool ContainsCjk(string token)
{
return CjkRegex().IsMatch(token);
}
private static IEnumerable<string> BuildNGrams(string token, int n)
{
if (token.Length < n)
{
yield break;
}
for (var i = 0; i <= token.Length - n; i++)
{
yield return token.Substring(i, n);
}
}
private static void AddTerm(List<string> terms, string candidate)
{
if (string.IsNullOrWhiteSpace(candidate) || candidate.Length < 2)
{
return;
}
terms.Add(candidate);
}
[GeneratedRegex(@"[\p{L}\p{N}]+", RegexOptions.Compiled | RegexOptions.CultureInvariant)]
private static partial Regex TokenRegex();
[GeneratedRegex(@"[\u4E00-\u9FFF]", RegexOptions.Compiled | RegexOptions.CultureInvariant)]
private static partial Regex CjkRegex();
}
/// <summary>
/// 搜索关键词分析结果。
/// </summary>
public sealed record SearchKeywordAnalysis(
string NormalizedKeyword,
IReadOnlyList<string> QueryTerms,
IReadOnlyList<string> HighlightTerms
)
{
public static readonly SearchKeywordAnalysis Empty = new(string.Empty, [], []);
}
⚠⚠ 以下内容为AI分析的结果,请根据实际情况进行判断。
这是一个用于搜索关键词分析的工具类,主要用于处理用户输入的搜索关键词,并生成用于查询和高亮显示的词条。以下是详细解释:
主要功能
1. 关键词分析 (Analyze 方法)
- 输入处理:接收用户输入的关键词字符串
- 标准化:通过
Normalize方法清理和格式化输入 - 词条提取:使用正则表达式提取有效的词条(字母和数字组合)
- 差异化处理:
- 中文处理:检测包含中日韩(CJK)字符的词条,生成2-gram分词
- 英文处理:将英文词条转换为小写用于查询,保持原大小写用于高亮
2. 词条管理
- 去重:使用
StringComparer.OrdinalIgnoreCase进行大小写不敏感的去重 - 排序:按词条长度降序排列,然后按字母顺序排列
- 限制:
- 查询词条最多8个 (
MaxQueryTerms) - 高亮词条最多24个 (
MaxHighlightTerms)
- 查询词条最多8个 (
3. 辅助功能
BuildRegexPattern 方法
- 将词条列表转换为正则表达式模式
- 对特殊字符进行转义处理
- 按长度降序排列,防止短词匹配覆盖长词
私有辅助方法
Normalize:清理输入字符串,移除多余空白字符ContainsCjk:检测是否包含中日韩字符BuildNGrams:为中文文本生成N-gram分词AddTerm:添加有效词条(长度至少2个字符)
4. 正则表达式(使用源生成器)
TokenRegex:匹配字母和数字组合的词条CjkRegex:匹配中日韩汉字字符范围
设计特点
- 多语言支持:兼容中英文混合搜索
- 性能优化:使用编译的正则表达式和源生成器
- 灵活性:分离查询词条和高亮词条,满足不同场景需求
- 健壮性:完善的空值检查和边界条件处理
使用场景
适用于搜索引擎、内容管理系统等需要处理多语言搜索关键词的场景,特别是需要同时支持精确查询和关键词高亮显示的应用。
评论加载中...