敏感词过滤能够防止一些不怀好心的用户破坏网络环境,防止卖片哥用自己的名字之类的打广告。
过滤速度慢
单纯的过滤一些关键字是非常简单的。绝大部分的语言都内置了replace功能,单纯的用replace都可以堆出敏感词过滤。但是这么做的过滤效率通常很低。正则表达式一般的速度也很慢,所以直接这样过滤数量庞大的敏感词不合适。
过滤代码复杂
现代应用中,用户的输入往往不是一个单独的字段,而是有很多文本字段的object对象,而编程者要对每个object的每个string类型字段、甚至string[]等单独调用一次过滤函数,这会导致代码变得很复杂,而且可读性不佳,看起来也很丑,写起来也烦(花很多时间写没水平的重复代码)
现代有些应用采用前端过滤的方法,原因是前端过滤不占用服务器资源。但是这导致前端代码复杂化,而且前端过滤速度一般较慢。
为了完美解决上方的两个问题,LimFx封装了专门的BadWordService,帮助开发者快速地对任何object的所有字段进行快速过滤。
BadWordService的过滤算法使用ToolGood.Word开源库,其搜索速度比标准c#正则匹配速度快8.8万倍,完美解决过滤慢的问题。
首先,BadWordService是LimFx.Common的一部分,目前不能单独获取。请通过引用LimFx.Common获取它的功能。BadWordService对ToolGood.Word的过滤方法进行封装,目前提供两个过滤函数BadWordFucker和BadWordFuckDeep。
我们通过例子来说明它们的用法:
using LimFx.Business.Services;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Collections.Generic;
namespace LimFx.Common.Test
{
class Bad
{
public string bad1 { get; set; }
[BadWordIgnore]
public string bad2 { get; set; }
public string bad3 { get; set; }
public string[] bad4 { get; set; }
public List<string> bad5 { get; set; }
public Bad innerBad { get; set; }
[BadWordIgnore]
public Bad innerGood { get; set; }
}
[TestClass]
public class BadWordFuckerTest
{
BadWordService badWordService;
[TestInitialize]
public void Init()
{
badWordService = new BadWordService();
}
[TestMethod]
public void TestBadWordFucker()
{
var temp = badWordService.BadwordsFucker(GetNewBad());
Assert.AreEqual("****", temp.bad1);
Assert.AreNotEqual("****", temp.bad2);
Assert.AreEqual("****", temp.bad3);
Assert.AreEqual("****", temp.bad4[0]);
Assert.AreEqual("****", temp.bad5[0]);
}
[TestMethod]
public void TestBadWordFuckerDeep()
{
var temp1 = badWordService.BadwordsFuckerDeep(new Bad
{
innerBad = GetNewBad(),
innerGood = GetNewBad()
});
var temp = temp1.innerBad;
Assert.AreEqual("****", temp.bad1);
Assert.AreEqual("****", temp.bad3);
Assert.AreEqual("****", temp.bad4[0]);
Assert.AreEqual("****", temp.bad5[0]);
temp = temp1.innerGood;
Assert.AreNotEqual("****", temp.bad1);
Assert.AreNotEqual("****", temp.bad3);
Assert.AreNotEqual("****", temp.bad4[0]);
Assert.AreNotEqual("****", temp.bad5[0]);
}
Bad GetNewBad()
{
return new Bad
{
bad1 = "****",
bad2 = "****",
bad3 = "****",
bad4 = new[] { "****", "****" },
bad5 = new List<string> { "****" }
};
}
}
}
可以看到,BadWordFucker对Bad类中的所有string、string[]和IList<string>类型的字段进行了过滤,BadWordFuckDeep则递归地对其内部属性中的string、string[]和IList<string>类型字段也进行了过滤。也就是说使用这两个函数,开发人员将不再需要对不同的object写不同的敏感词过滤函数。只需要直接调用这两个函数即可!
而BadWordIgnoreAttribute则会让过滤函数忽略带有它的字段。
我们也对性能做了一些BenchMark,在用BadWordFuckDeep过滤每层有5000个单词的字段两层嵌套的object的时候,平均用时不到2ms。
本文章使用limfx的vsocde插件快速发布