【愚公系列】2023年03月 .NET CORE工具案例-ToolGood.Words敏感词过滤
前言
1.什么是敏感词过滤
敏感词过滤是一种处理网络内容的技术,可以检测和过滤出网络中的敏感词汇。它通过给定的关键字或字符串,判断网络内容是否包含某些敏感信息,从而防止违反法律法规的信息流通。
通常,可以使用两种方法来过滤敏感词:
• 黑名单过滤:即定义一个黑名单,将所有敏感词择记录在其中,然后对输入的文本进行对比,如果发现有敏感词,就将其过滤掉。
• 白名单过滤:即定义一个白名单,将所有不敏感的词汇记录在其中,然后对输入的文本进行对比,如果发现有不在白名单中的词汇,就将其过滤掉。
2.ToolGood.Words是什么
ToolGood.Words是一款高性能非法词(敏感词)检测组件,附带繁体简体互换,支持全角半角互换,获取拼音首字母,获取拼音字母,拼音模糊搜索等功能。
C#语言,使用StringSearchEx2.Replace过滤,在48k敏感词库上的过滤速度超过3亿字符每秒。(cpu i7 8750h)
3.ToolGood.Words的相关概念
ToolGood.Words的敏感词检测类主要有:StringSearch、StringSearchEx、StringSearchEx2、WordsSearch、WordsSearchEx、WordsSearchEx2、IllegalWordsSearch介绍如下:
• StringSearch、StringSearchEx、StringSearchEx2、StringSearchEx3:搜索FindFirst方法返回结果为string类型。
• WordsSearch、WordsSearchEx、WordsSearchEx2、WordsSearchEx3:搜索FindFirst方法返回结果为WordsSearchResult类型, WordsSearchResult不仅仅有关键字,还有关键字的开始位置、结束位置,关键字序号等。
• IllegalWordsSearch:过滤非法词(敏感词)专用类,可设置跳字长度,默认全角转半角,忽略大小写,跳词,重复词,黑名单,搜索FindFirst方法返回为IllegalWordsSearchResult,有关键字,对应原文,开始、位置,黑名单类型。
• IllegalWordsSearch、StringSearchEx、StringSearchEx2、WordsSearchEx、WordsSearchEx2 使用Save、Load方法,可以加快初始化。
• 共同方法有:SetKeywords、ContainsAny、FindFirst、FindAll、Replace
• IllegalWordsSearch独有方法:SetSkipWords(设置跳词)、SetBlacklist(设置黑名单)。
• IllegalWordsSearch字段UseIgnoreCase:设置是忽略否大小写,必须在SetKeywords方法之前,注:使用Load方法则该字段无效。
• StringSearchEx3、WordsSearchEx3为指针版优化版,实测时发现性能浮动比较大。
ToolGood.Words的源码网站:https://github.com/toolgood/ToolGood.Words
一、ToolGood.Words敏感词过滤
1.安装包
ToolGood.Words
2.定义模型类
//用于核查敏感词
public class MinganCheckInput
{
[MinGanCheck]
public string Text { get; set; }
}
//用于替换敏感词
public class MinganReplaceInput
{
[MinGanReplace]
public string Text { get; set; }
}
3.定义敏感词实现类
1、接口
public interface IMinGanCheckValidator
{
ValidationResult IsValid(object value, ValidationContext validationContext);
}
public interface IMinGanReplaceValidator
{
void Replace(object value, ValidationContext validationContext);
}
2、实现类
public class MinGanCheckValidator : IMinGanCheckValidator
{
public ValidationResult IsValid(object value, ValidationContext validationContext)
{
if (value is string v)
{
if (!String.IsNullOrEmpty(v))
{
if (MinGanProvider.Instance.IllegalWordsSearch.ContainsAny(v))
{
return new ValidationResult("存在敏感词", new[] { validationContext.MemberName });
}
// 检查拼音
if (MinGanProvider.Instance.IllegalWordsSearch.ContainsAny(WordsHelper.GetPinyin(v)))
{
return new ValidationResult("存在敏感词",new []{ validationContext.MemberName });
}
// todo:其他变种
}
}
return ValidationResult.Success;
}
}
public class MinGanReplaceValidator : IMinGanReplaceValidator
{
public void Replace(object value, ValidationContext validationContext)
{
if (value is string v)
{
if (!String.IsNullOrEmpty(v))
{
v = MinGanProvider.Instance.IllegalWordsSearch.Replace(v);
SetPropertyByName(validationContext.ObjectInstance,validationContext.MemberName, v);
}
}
}
static bool SetPropertyByName(Object obj, string name, Object value)
{
var type = obj.GetType();
var prop = type.GetProperty(name, BindingFlags.Public | BindingFlags.Instance);
if (null == prop || !prop.CanWrite) return false;
prop.SetValue(obj, value, null);
return true;
}
}
4.定义特性
/// <summary>
/// 敏感词检查的特性,一匹配就抛异常
/// </summary>
[AttributeUsage(AttributeTargets.Property)]
public class MinGanCheck : ValidationAttribute
{
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
return validationContext.GetService<IMinGanCheckValidator>().IsValid(value, validationContext);
}
}
/// <summary>
/// 敏感词替换
/// </summary>
[AttributeUsage(AttributeTargets.Property)]
public class MinGanReplace : ValidationAttribute
{
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
validationContext.GetService<IMinGanReplaceValidator>().Replace(value, validationContext);
return ValidationResult.Success;
}
}
5.添加配置文件
{
"IllegalKeywords": [
"xxxxxxx",
]
}
{
"IllegalUrls": [
"xxxxxxx",
]
}
#region 添加配置文件
builder.Configuration.AddJsonFile("IllegalKeywords.json", optional: false, reloadOnChange: true);// 配置可热重载
builder.Configuration.AddJsonFile("IllegalUrls.json", optional: false, reloadOnChange: true);// 配置可热重载
#endregion
6.配置热更新
public sealed class MinGanProvider
{
private static readonly Lazy<MinGanProvider>
lazy =
new Lazy<MinGanProvider>
(() => new MinGanProvider());
public static MinGanProvider Instance { get { return lazy.Value; } }
private MinGanProvider()
{
IllegalWordsSearch = new IllegalWordsSearch();
}
public readonly IllegalWordsSearch IllegalWordsSearch;
public void SetKeys(List<string> keys)
{
if (keys!=null&&keys.Any())
{
var allKeys = new List<string>();
foreach (var k in keys)
{
allKeys.Add(k); // 增加词汇
allKeys.Add(WordsHelper.ToTraditionalChinese(k)); // 增加繁体
allKeys.Add(WordsHelper.GetPinyin(k)); // 增加拼音
}
IllegalWordsSearch.SetKeywords(allKeys);
}
}
}
#region 配置热更新
MinGanProvider.Instance.SetKeys(builder.Configuration.GetSection("IllegalKeywords").Get<List<string>>());
ChangeToken.OnChange(() => app.Configuration.GetReloadToken(), () =>
{
// 敏感词重载
MinGanProvider.Instance.SetKeys(builder.Configuration.GetSection("IllegalKeywords").Get<List<string>>());
});
#endregion
7.运行
[ApiController]
[Route("[controller]/[action]")]
public class MinganController : ControllerBase
{
[HttpGet]
public string Check([FromQuery]MinganCheckInput input)
{
return input.Text;
}
[HttpGet]
public string Replace([FromQuery]MinganReplaceInput input)
{
return $"替换后的字段为:{input.Text}";
}
}
测试
- 点赞
- 收藏
- 关注作者
评论(0)