Giter VIP home page Giter VIP logo

toolgood / toolgood.words Goto Github PK

View Code? Open in Web Editor NEW
4.5K 4.5K 836.0 104.26 MB

一款高性能敏感词(非法词/脏字)检测过滤组件,附带繁体简体互换,支持全角半角互换,汉字转拼音,模糊搜索等功能。

License: Apache License 2.0

C# 10.48% Java 2.89% Go 1.75% JavaScript 68.95% HTML 0.08% Python 15.84% Batchfile 0.01%
aho-corasick dotnet filter golang java javascript pinyin python sensitive-word-filter string-matching stringsearch text-filter text-matching text-search textfilter textsearch trietree word-filter wordfilter wordssearch

toolgood.words's Introduction

ToolGood.Words

一款高性能非法词(敏感词)检测组件,附带繁体简体互换,支持全角半角互换,获取拼音首字母,获取拼音字母,拼音模糊搜索等功能。

C#语言,使用StringSearchEx2.Replace过滤,在48k敏感词库上的过滤速度超过3亿字符每秒。(cpu i7 8750h)

csharp 文件夹说明:

ToolGood.Pinyin.Build:          生成词的拼音
ToolGood.Pinyin.Pretreatment:   生成拼音预处理,核对拼音,词组最小化
ToolGood.Transformation.Build: 生成简体繁体转换文档,更新时文档放在同一目录下,词库参考 https://github.com/BYVoid/OpenCC
ToolGood.Words.Contrast:        字符串搜索对比
ToolGood.Words.Test:            单元测试
ToolGood.Words:                 本项目源代码

非法词(敏感词)检测(字符串搜索)

非法词(敏感词)检测类:StringSearchStringSearchExStringSearchEx2WordsSearchWordsSearchExWordsSearchEx2IllegalWordsSearch;

  • StringSearchStringSearchExStringSearchEx2StringSearchEx3: 搜索FindFirst方法返回结果为string类型。
  • WordsSearchWordsSearchExWordsSearchEx2WordsSearchEx3: 搜索FindFirst方法返回结果为WordsSearchResult类型, WordsSearchResult不仅仅有关键字,还有关键字的开始位置、结束位置,关键字序号等。
  • IllegalWordsSearch: 过滤非法词(敏感词)专用类,可设置跳字长度,默认全角转半角,忽略大小写,跳词,重复词,黑名单, 搜索FindFirst方法返回为IllegalWordsSearchResult,有关键字,对应原文,开始、位置,黑名单类型。
  • IllegalWordsSearchStringSearchExStringSearchEx2WordsSearchExWordsSearchEx2 使用SaveLoad方法,可以加快初始化。
  • 共同方法有:SetKeywordsContainsAnyFindFirstFindAllReplace
  • IllegalWordsSearch独有方法:SetSkipWords(设置跳词)、SetBlacklist(设置黑名单)。
  • IllegalWordsSearch字段UseIgnoreCase:设置是忽略否大小写,必须在SetKeywords方法之前,注:使用Load方法则该字段无效。
  • StringSearchEx3WordsSearchEx3为指针版优化版,实测时发现性能浮动比较大。
    string s = "**|国人|zg人";
    string test = "我是**人";

    StringSearch iwords = new StringSearch();
    iwords.SetKeywords(s.Split('|'));
    
    var b = iwords.ContainsAny(test);
    Assert.AreEqual(true, b);

    var f = iwords.FindFirst(test);
    Assert.AreEqual("**", f);

    var all = iwords.FindAll(test);
    Assert.AreEqual("**", all[0]);
    Assert.AreEqual("国人", all[1]);
    Assert.AreEqual(2, all.Count);

    var str = iwords.Replace(test, '*');
    Assert.AreEqual("我是***", str);

非法词(敏感词)检测(字符串搜索)(支持通配符)

非法词(敏感词)检测类:StringMatchStringMatchExWordsMatchWordsMatchEx

支持部分正则表达式类型:.(点)?(问号) [](方括号) (|)(括号与竖线)

    string s = ".[中美]国|国人|zg人";
    string test = "我是**人";

    WordsMatch wordsSearch = new WordsMatch();
    wordsSearch.SetKeywords(s.Split('|'));

    var b = wordsSearch.ContainsAny(test);
    Assert.AreEqual(true, b);

    var f = wordsSearch.FindFirst(test);
    Assert.AreEqual("是**", f.Keyword);

    var alls = wordsSearch.FindAll(test);
    Assert.AreEqual("是**", alls[0].Keyword);
    Assert.AreEqual(".[中美]国", alls[0].MatchKeyword);
    Assert.AreEqual(1, alls[0].Start);
    Assert.AreEqual(3, alls[0].End);
    Assert.AreEqual(0, alls[0].Index);//返回索引Index,默认从0开始
    Assert.AreEqual("国人", alls[1].Keyword);
    Assert.AreEqual(2, alls.Count);

    var t = wordsSearch.Replace(test, '*');
    Assert.AreEqual("我****", t);

繁体简体互换、全角半角互换、数字转成中文大写、拼音操作

    // 转成简体
    WordsHelper.ToSimplifiedChinese("我愛中國");
    WordsHelper.ToSimplifiedChinese("我愛中國",1);// 港澳繁体 转 简体
    WordsHelper.ToSimplifiedChinese("我愛中國",2);// **正体 转 简体
    // 转成繁体
    WordsHelper.ToTraditionalChinese("我爱**");
    WordsHelper.ToTraditionalChinese("我爱**",1);// 简体 转 港澳繁体
    WordsHelper.ToTraditionalChinese("我爱**",2);// 简体 转 **正体
    // 转成全角
    WordsHelper.ToSBC("abcABC123");
    // 转成半角
    WordsHelper.ToDBC("abcABC123");
    // 数字转成中文大写
    WordsHelper.ToChineseRMB(12345678901.12);
    // 中文转成数字
    WordsHelper.ToNumber("壹佰贰拾叁亿肆仟伍佰陆拾柒万捌仟玖佰零壹元壹角贰分");
    // 获取全拼
    WordsHelper.GetPinyin("我爱**");//WoAiZhongGuo   
    WordsHelper.GetPinyin("我爱**",",");//Wo,Ai,Zhong,Guo   
    WordsHelper.GetPinyin("我爱**",true);//WǒÀiZhōngGuó

    // 获取首字母
    WordsHelper.GetFirstPinyin("我爱**");//WAZG
    // 获取全部拼音
    WordsHelper.GetAllPinyin('传');//Chuan,Zhuan
    // 获取姓名
    WordsHelper.GetPinyinForName("单一一")//ShanYiYi
    WordsHelper.GetPinyinForName("单一一",",")//Shan,Yi,Yi
    WordsHelper.GetPinyinForName("单一一",true)//ShànYīYī
拼音分支

ToolGood.Words.Pinyin 追求更快的加载速度(目前只有C#代码)。

拼音匹配

PinyinMatch:方法有SetKeywordsSetIndexsFindFindIndex

PinyinMatch<T>:方法有SetKeywordsFuncSetPinyinFuncSetPinyinSplitCharFind

    string s = "北京|天津|河北|辽宁|吉林|黑龙江|山东|江苏|上海|浙江|安徽|福建|江西|广东|广西|海南|河南|湖南|湖北|山西|内蒙古|宁夏|青海|陕西|甘肃|**|四川|贵州|云南|重庆|西藏|香港|澳门|**";

    PinyinMatch match = new PinyinMatch();
    match.SetKeywords(s.Split('|').ToList());

    var all = match.Find("BJ");
    Assert.AreEqual("北京", all[0]);
    Assert.AreEqual(1, all.Count);

    all = match.Find("北J");
    Assert.AreEqual("北京", all[0]);
    Assert.AreEqual(1, all.Count);

    all = match.Find("北Ji");
    Assert.AreEqual("北京", all[0]);
    Assert.AreEqual(1, all.Count);

    all = match.Find("S");
    Assert.AreEqual("山东", all[0]);
    Assert.AreEqual("江苏", all[1]);

    var all2 = match.FindIndex("BJ");
    Assert.AreEqual(0, all2[0]);
    Assert.AreEqual(1, all.Count);

性能对比

执行10万次性能对比,结果如下:

10W次性能对比

注:C#自带正则很慢,StringSearchEx2.ContainsAnyRegex.IsMatch效率的8.8万倍多,跟关键字数量有关。

Regex.Matches的运行方式跟IQueryable的类似,只返回MatchCollection,还没有计算。

在 Find All测试中, (检测出的文本中有敏感词汇,就不显示了,大家可自行调试查看)。

FastFilter只能检测出7个

StringSearch检测出14个

插曲:在细查Regex.Matches神奇3ms,我发现Regex.Matches有一个小问题,

Regex.Matches只能检测出11个

其他语言实现

Lua版本

作者:wenlifan 地址:https://github.com/wenlifan/SensitiveWordFilter

推荐一下

《ToolGood 内容审核系统》正式开源,Windows、Linux双平台,内存占用小于100M。

官网:https://toolgood.com/

开源代码:https://github.com/toolgood/ToolGood.TextFilter

敏感信息过滤研究会,Q群:128994346(已满)

本人不是老师,请不要提关于项目使用、加载等简单问题。

敏感词相关文章

1、敏感词过滤方案那些事

2、普通公司敏感词审核制度

3、新人小白过滤敏感词方案

4、网络常用敏感词过滤方法

5、ToolGood.Words算法过滤敏感词优化原理 (收费30元,一顿KFC)

6、ToolGood.TextFilter开源代码优化详解 (收费300元) 与IllegalWordsSearch算法进行对比,阐述了ToolGood.TextFilter过滤算法优化点,如何减少内存使用量。 还有一小部分未写好,心急的人可以先买,我会持续更新。

7、正则转DFA算法(C#版、JAVA版) (收费30元,一顿KFC) ToolGood.TextFilter的一个核心算法就使用到正则转DFA。

8、C#版图片鉴黄(收费30元,一顿KFC)

比特币私钥碰撞机

比特币私钥碰撞机,利用电脑空闲性能(3G内存),搏25万枚比特币。

比特币私钥碰撞机(收费50元)

比特币私钥碰撞机源码(收费500元)

toolgood.words's People

Contributors

androidharry avatar dependabot[bot] avatar toolgood avatar zml4518079 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

toolgood.words's Issues

java版IllegalWordsSearch部分敏感词搜索不到

  • 部分敏感词搜不到,不知道是不是量词的关系
                String test = "一,二二,三三三,四四四四,五五五五五,六六六六六六";
		List<String> list = new ArrayList<String>();
		list.add("一");
		list.add("二二");
		list.add("三三三");
		list.add("四四四四");
		list.add("五五五五五");
		list.add("六六六六六六");
		System.out.println("IllegalWordsSearch run Test.");

		IllegalWordsSearch iwords = new IllegalWordsSearch();
		iwords.SetKeywords(list);

		boolean b = iwords.ContainsAny(test);
		if (b == false) {
			System.out.println("ContainsAny is Error.");
		}

		IllegalWordsSearchResult f = iwords.FindFirst(test);
		if (f.Keyword.equals("一") == false) {
			System.out.println("FindFirst is Error.");
		}

		List<IllegalWordsSearchResult> all = iwords.FindAll(test);
		if (all.get(0).Keyword.equals("一") == false) {
			System.out.println("FindAll is Error.");
		}
		if (all.get(1).Keyword.equals("二二") == false) {
			System.out.println("FindAll is Error.");
		}
		if (all.get(2).Keyword.equals("三三三") == false) {
			System.out.println("FindAll is Error.");
		}
		if (all.get(3).Keyword.equals("四四四四") == false) {
			System.out.println("FindAll is Error.");
		}
		if (all.get(4).Keyword.equals("五五五五五") == false) {
			System.out.println("FindAll is Error.");
		}
		if (all.get(5).Keyword.equals("六六六六六六") == false) {
			System.out.println("FindAll is Error.");
		}
  • 敏感词找不到
                String test = "jameson吃饭";
		List<String> list = new ArrayList<String>();
		list.add("jameson吃饭");
		list.add("吃饭jameson");
		System.out.println("IllegalWordsSearch run Test.");

		IllegalWordsSearch iwords = new IllegalWordsSearch();
		iwords.SetKeywords(list);

		boolean b = iwords.ContainsAny(test);
		if (b == false) {
			System.out.println("ContainsAny is Error.");
		}

		IllegalWordsSearchResult f = iwords.FindFirst(test);
		if (f.Keyword.equals("jameson吃饭") == false) {
			System.out.println("FindFirst is Error.");
		}
  • WordsSearchEx、WordsSearchEx2、StringSearchEx、StringSearchEx2也有部分词无法搜索

某个关键字不能替换

@test
public void replace() {
IllegalWordsSearch search = new IllegalWordsSearch();
search.SetKeywords(Arrays.asList("test", "world", "this", "hello", "monster"));
String result = search.Replace("test, hahaha, this is a hello world", '*');
System.out.println(result);
}

输出
****, hahaha, **** is a hello *****
hello 为什么替换不掉呢?

过滤时临时添加不过滤项

需求是所有的客户原则上要过滤全部的敏感词,但是个别用户有白名单.这样在这个用户在过滤的时候就需要跳过这些单词.
我不知道是重新初始化好,还是每找到一个后再验证是否在白名单好.现在我选的是后者.

有个别乱码现象

utf8中文有个别乱码现象,用的是IllegalWordsSearch
使用前
{"id":"政府行业###**###**人民###人民大学","count":725},{"id":"政府行业###**###**人民###人民共和国","count":279},{"id":"政府行业###**###**人民###**人民解放军","count":227}
使用后
{"id":"政府行业###**###**人民###人民大学","count":725},{"id":"政府行业###**###**人��###人民共和国","count":279},{"id":"政府行业###**###**人民###**人民解放军","count":227}
可以看到“民”这个字在多个地方出现,但只有一个是乱码

您好,有关跳词和黑名单设置

这两个功能不太懂有什么用,跳词设置后,用FindAll依旧能查出结果,看来不是设置能跳过某个词的功能,那个黑名单级别也是没怎么看懂,作者能不能说明下?谢谢了

PinYinSearch大量占用内存有什么好的方案

我实际测了一下,使用了67万关键字,12M文本,SetKeywords,2秒左右,占用内存1.7G,这还不算多大的数据情况下,有点招不住,另外,看到FirstPinYinNode=>PinYinNode=>ChineseNode,也就是说树的深度随着指数增加,在大量数据的情况假设按管件字20字,深度60,每三级节点,第一级26字母,第二级,常见拼音406个,第三级,中文字符20903个,这样下来,搜索的深度和广度是否太大了一些,是否有更好的解决方案,能否在设计上做一些优化。

长短不一的敏感词会重复命中_要如何设置

         var iws = new IllegalWordsSearch();
        iws.SetKeywords("烦死了,烦,死,了".Split(','));
        iws.UseDuplicateWordFilter = true;
        iws.UseIgnoreCase = true;
        iws.UseDBCcaseConverter = true;

        //act
        List<IllegalWordsSearchResult> res = iws.FindAll("果然是烦死了");

        //assert
        //现在的问题是,res.count=4,会同时命中:“烦死了”“烦”“死”“了”这四个敏感词。
        //有办法设置,按最小长度或者最大长度命中,不要重复么。

        //如何确保只命中一次,比如只命中“烦死了”
        Assert.AreEqual(1, res.Count);

        //或者说,只命中三次,比如命中了“烦”“死”“了”
        Assert.AreEqual(3, res.Count);`

aa

敏感词越多导致初始化极慢

你好, 测试中1W多的敏感词加载需要10多秒, 如果到5万,甚至10万敏感词,那么初始化基本卡死掉了,无法使用, 有劳作者测试和改进下

内存占用

你好,
使用了你的库 c# 版本,发现内存占用很大。

程序启动的时候调用二十次左右 WordsHelper.GetFirstPinyin,内存占用会飙升至 1G 左右。
有什么好办法可以减小内存占用吗?

memory profile 结果
image

能不能在wiki里添加每个API支持的字符集?

不错的工具,做项目正好用到.我看代码里面现在是这样写的

        /// <summary>
        /// 获取单字拼音
        /// </summary>
        /// <param name="ch"></param>
        /// <returns></returns>
        public static String Get(Char ch)
        {
            if (ch >= 0x4e00 && ch <= 0x9faf) {

能添加一个具体说明注明每个API已经支持的字符集和计划支持哪些就更好了

IllegalWordsSearch 无法识别数字敏感字?

`
string text = "A1002481003吃饭";
var keywords = new string[] { "248" };
var iws = new IllegalWordsSearch();
var ss = new StringSearch();
var sse = new StringSearchEx();
iws.SetKeywords(keywords);

    //无结果
    var iwsFirst = iws.FindFirst(text);
    var iwsAll = iws.FindAll(text);

    //正常识别出248
    ss.SetKeywords(keywords);
    var ssFirst = ss.FindFirst(text);
    var ssAll = ss.FindAll(text);
    
    //正常识别出248
    sse.SetKeywords(keywords);
    var sseFirst = sse.FindFirst(text);
    var sseAll = sse.FindAll(text);

`
1
2
3

WordsHelper.ToChineseRMB输出错误

假如输入是10348.95
正确的输出应该是:壹万零叁佰肆拾捌元玖角伍分
但现在输出了:壹萬零叁佰肆拾捌元玖角伍分

万是不需要翻译成繁体的

有python版吗?

python通用性更强一些吧?
不知道有没有python版?
一般这种都是出一个http的接口,做基础服务用的.
python import tornado很方便.

敏感词管理

除了直接编辑敏感词 txt 文件,有没有暴露方法来管理敏感词?

SetSkipWords 是不是有问题?

public void SetSkipWords(string skipList)
{
_skipBitArray = new bool[char.MaxValue + 1];
if (skipList == null) {
for (int i = 0; i < _skipList.Length; i++) {
_skipBitArray[_skipList[i]] = true;
}
}
}

skipList参数根本没有使用????

有的偏僻汉字不能识别出拼音

谢谢您的软件,在多音字识别方面超出了很多同类软件。不过还有的偏僻汉字不能识别出拼音,比如这几个字:“㘄䉄䬋䮚䚏㭁䖆”,望改进。
"㘄": "lēng",
"䉄": "léng",
"䬋": "léng",
"䮚": "lèng",
"䚏": "lèng,lì,lìn",
"㭁": "réng",
"䖆": "niàng"

方法名统一一下吧

拼音:英文翻译就是“Pinyin”,项目中有些方法名是“PinYin”,有些又是"Pinyin",建议都用“Pinyin”

字符串中的数字和字母关键字无法识别

string text = "A10021003吃饭";
var keywords = new string[] { "1","A","2","0",""};
var iws = new IllegalWordsSearch();
var ss = new StringSearch();
var sse = new StringSearchEx();

iws.SetKeywords(keywords);
iws.UseIgnoreCase = true;
iws.UseDBCcaseConverter = true;
var iwsFirst = iws.FindFirst(text);
var iwsAll = iws.FindAll(text);

ss.SetKeywords(keywords);
var ssFirst = iws.FindFirst(text);
var ssAll = iws.FindAll(text);

sse.SetKeywords(keywords);
var sseFirst = iws.FindFirst(text);
var sseAll = iws.FindAll(text);

为什么上述代码的结果会如下所示,数字和字母没有识别出来,汉字关键字是吃,怎么识别出是吃饭?

使用的库版本是2.3.3

image

繁简转换缺失 勳/勛 vs 勋

勋 ->转繁体只有 勛 这个不算问题,因为"勳"是异体字
但是 勳->转简体时还是 勳 这个建议修正码表.

最新版本有问题

PinYinSearchExTest.cs 和 PinYinSearchTest.cs 这两个文件,默认是错误的,因为命名空间的原因。

result not right.

private IllegalWordsSearch illegalWordsSearch = null;
illegalWordsSearch = new IllegalWordsSearch();
private string s = "**|zg人|abc";
illegalWordsSearch.SetKeywords(s.Split('|'));
illegalWordsSearch.Replace("我是中美国人厉害**完美abcddb好的", '*');

then result is:我是中美国人厉害************
expected result is:我是中美国人厉害完美*ddb好的

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.