最近弄了一个用户发表评论的功能,用户上传了评论,再文章下可以看到自己的评论,但作为社会主义接班人,践行社会主义核心价值观,所以给评论敏感词过滤的功能不可少,在网上找了资料,发现已经有非常成熟的解决方案。 常用的方案用这么两种
1.全文搜索,逐个匹配。这种听起来就不够高大上,在数据量大的情况下,会有效率问题,文末有比较
2.DFA算法-确定有限状态自动机 附上百科链接确定有限状态自动机
DFA算法介绍
DFA是一种计算模型,数据源是一个有限个集合,通过当前状态和事件来确定下一个状态,即 状态+事件=下一状态,由此逐步构建一个有向图,其中的节点就是状态,所以在DFA算法中只有查找和判断,没有复杂的计算,从而提高算法效率
参考文章 Java实现敏感词过滤
实现逻辑
构造数据结构
将敏感词转换成树结构,举例敏感词有着这么几个 ['日本鬼子','日本人','日本男人'] ,那么数据结构如下(图片引用参考文章)
每个文字是一个节点,连续的节点组成一个词, 日本人 对应的就是中间的那条链,我们可以使用对象或者map来构建树,这里的栗子采用 map 构建节点,每个节点中有个状态标识,用来表示当前节点是不是最后一个,每条链路必须要有个终点节点,先来看下构建节点的流程图
判断逻辑
先从文本的第一个字开始检查,比如 你我是日本鬼子 ,第一个字 你 ,在树的第一层找不到这个节点,那么继续找第二个字,到了 日 的时候,第一层节点找到了,那么接着下一层节点中查找 本 ,同时判断这个节点是不是结尾节点,若是结尾节点,则匹配成功了,反之继续匹配
代码实现
####构造数据结构
/** * @description * 构造敏感词map * @private * @returns */ private makeSensitiveMap(sensitiveWordList) { // 构造根节点 const result = new Map(); for (const word of sensitiveWordList) { let map = result; for (let i = 0; i < word.length; i++) { // 依次获取字 const char = word.charAt(i); // 判断是否存在 if (map.get(char)) { // 获取下一层节点 map = map.get(char); } else { // 将当前节点设置为非结尾节点 if (map.get('laster') === true) { map.set('laster', false); } const item = new Map(); // 新增节点默认为结尾节点 item.set('laster', true); map.set(char, item); map = map.get(char); } } } return result; }
最终map结构如下
查找敏感词
/** * @description * 检查敏感词是否存在 * @private * @param {any} txt * @param {any} index * @returns */ private checkSensitiveWord(sensitiveMap, txt, index) { let currentMap = sensitiveMap; let flag = false; let wordNum = 0;//记录过滤 let sensitiveWord = ''; //记录过滤出来的敏感词 for (let i = index; i < txt.length; i++) { const word = txt.charAt(i); currentMap = currentMap.get(word); if (currentMap) { wordNum++; sensitiveWord += word; if (currentMap.get('laster') === true) { // 表示已到词的结尾 flag = true; break; } } else { break; } } // 两字成词 if (wordNum < 2) { flag = false; } return { flag, sensitiveWord }; } /** * @description * 判断文本中是否存在敏感词 * @param {any} txt * @returns */ public filterSensitiveWord(txt, sensitiveMap) { let matchResult = { flag: false, sensitiveWord: '' }; // 过滤掉除了中文、英文、数字之外的 const txtTrim = txt.replace(/[^\u4e00-\u9fa5\u0030-\u0039\u0061-\u007a\u0041-\u005a]+/g, ''); for (let i = 0; i < txtTrim.length; i++) { matchResult = checkSensitiveWord(sensitiveMap, txtTrim, i); if (matchResult.flag) { console.log(`sensitiveWord:${matchResult.sensitiveWord}`); break; } } return matchResult; }
效率
为了看出DFA的效率,我做了个简单的小测试,测试的文本长度为5095个汉字,敏感词词库中有2000个敏感词,比较的算法分别为 DFA算法 和 String原生对象提供的 indexOf API做比较
// 简单的字符串匹配-indexOf ensitiveWords.forEach((word) => { if (ss.indexOf(word) !== -1) { console.log(word) } })
分别将两个算法执行100次,得到如下结果
可直观看出, DFA 的平均耗时是在1ms左右,最大为5ms; indexOf 方式的平均耗时在9ms左右,最大为14ms,所以DFA效率上还是非常明显有优势的。
总结
以上所述是小编给大家介绍的js实现敏感词过滤算法及实现逻辑,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对网站的支持!
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!
稳了!魔兽国服回归的3条重磅消息!官宣时间再确认!
昨天有一位朋友在大神群里分享,自己亚服账号被封号之后居然弹出了国服的封号信息对话框。
这里面让他访问的是一个国服的战网网址,com.cn和后面的zh都非常明白地表明这就是国服战网。
而他在复制这个网址并且进行登录之后,确实是网易的网址,也就是我们熟悉的停服之后国服发布的暴雪游戏产品运营到期开放退款的说明。这是一件比较奇怪的事情,因为以前都没有出现这样的情况,现在突然提示跳转到国服战网的网址,是不是说明了简体中文客户端已经开始进行更新了呢?
更新日志
- 好薇2024《兵哥哥》1:124K黄金母盘[WAV+CUE]
- 胡歌.2006-珍惜(EP)【步升大风】【FLAC分轨】
- 洪荣宏.2014-拼乎自己看【华特】【WAV+CUE】
- 伊能静.1999-从脆弱到勇敢1987-1996精选2CD【华纳】【WAV+CUE】
- 刘亮鹭《汽车DJ玩主》[WAV+CUE][1.1G]
- 张杰《最接近天堂的地方》天娱传媒[WAV+CUE][1.1G]
- 群星《2022年度发烧天碟》无损黑胶碟 2CD[WAV+CUE][1.4G]
- 罗文1983-罗文甄妮-射雕英雄传(纯银AMCD)[WAV+CUE]
- 群星《亚洲故事香港纯弦》雨果UPMAGCD2024[低速原抓WAV+CUE]
- 群星《经典咏流传》限量1:1母盘直刻[低速原抓WAV+CUE]
- 庾澄庆1993《老实情歌》福茂唱片[WAV+CUE][1G]
- 许巍《在别处》美卡首版[WAV+CUE][1G]
- 林子祥《单手拍掌》华纳香港版[WAV+CUE][1G]
- 郑秀文.1997-我们的主题曲【华纳】【WAV+CUE】
- 群星.2001-生命因爱动听电影原创音乐AVCD【MEDIA】【WAV+CUE】