• 注册
  • 后端开发博客 后端开发博客 关注:0 内容:2416

    吴X凡绯闻女友小怡同学被骂到清空社交平台?各大平台连敏感词库都没有的吗?

  • 查看作者
  • 打赏作者
  • 当前位置: 职业司 > 后端开发 > 后端开发博客 > 正文
    • 后端开发博客
    • 敏感词都没有的平台

      最近某加拿大籍贯的 rapper 被曝私生活不检点,且极有可能涉及诱X未成年少女,成为一个 raper。

      吴X凡绯闻女友小怡同学被骂到清空社交平台?各大平台连敏感词库都没有的吗?

      当然至于是否属实,其实一个人是否是海王,微信、QQ 聊天记录里面记得清清楚楚。再上升到刑事案件的时候,TX 完全可以审查所有的历史记录。腾讯视频和某电鳗解约,也不见得毫无根据,毕竟利益相关。

      但是我在整个过程中却发现两个非常值得注意的地方:

      (1)其绯闻女友小怡同学,被骂到清空所有社交平台。作为吃瓜大户的 X 博,难道只会服务器瘫痪,不知道敏感词过滤吗?

      (2)举报者都美竹收到大量血|腥的照片,难道各大天天吹人工智能的平台,也没有过滤的功能吗?

      当然了,对于人工智能我一无所知。

      但是对于敏感词,最近写了一个小工具,如果各大平台需要的话,已经开源,欢迎自取。

      github.com/houbb/sensi…

      至少可以把美丽的中国话脱敏下面的样子:

      你 XXX 的,我 XXX 你 XXX,你 XXXX,XXX!!XXX!
      复制代码

      创作目的

      基于 DFA 算法实现,目前敏感词库内容收录 6W+(源文件 18W+,经过一次删减)。

      后期将进行持续优化和补充敏感词库,并进一步提升算法的性能。

      希望可以细化敏感词的分类,感觉工作量比较大,暂时没有进行。

      这里说一下愿景吧,愿景是成为第一好用的敏感词工具。

      当然,第一总是空虚的。

      吴X凡绯闻女友小怡同学被骂到清空社交平台?各大平台连敏感词库都没有的吗?

      特性

      • 6W+ 词库,且不断优化更新

      • 基于 DFA 算法,性能较好

      • 基于 fluent-api 实现,使用优雅简洁

      • 支持敏感词的判断、返回、脱敏等常见操作

      • 支持全角半角互换

      • 支持英文大小写互换

      • 支持数字常见形式的互换

      • 支持中文繁简体互换

      • 支持英文常见形式的互换

      • 支持用户自定义敏感词和白名单

      • 支持数据的数据动态更新,实时生效

      快速开始

      准备

      • JDK1.7+

      • Maven 3.x+

      Maven 引入

      <dependency>
      <groupId>com.github.houbb</groupId>
      <artifactId>sensitive-word</artifactId>
      <version>0.0.15</version>
      </dependency>
      复制代码

      api 概览

      SensitiveWordHelper 作为敏感词的工具类,核心方法如下:

      方法 参数 返回值 说明
      contains(String) 待验证的字符串 布尔值 验证字符串是否包含敏感词
      findAll(String) 待验证的字符串 字符串列表 返回字符串中所有敏感词
      replace(String, char) 使用指定的 char 替换敏感词 字符串 返回脱敏后的字符串
      replace(String) 使用 * 替换敏感词 字符串 返回脱敏后的字符串

      使用实例

      所有测试案例参见 SensitiveWordHelperTest

      判断是否包含敏感词

      final String text = "五星红旗迎风飘扬,毛主席的画像屹立在天安门前。";
      Assert.assertTrue(SensitiveWordHelper.contains(text));
      复制代码

      返回第一个敏感词

      final String text = "五星红旗迎风飘扬,毛主席的画像屹立在天安门前。";
      String word = SensitiveWordHelper.findFirst(text);
      Assert.assertEquals("五星红旗", word);
      复制代码

      返回所有敏感词

      final String text = "五星红旗迎风飘扬,毛主席的画像屹立在天安门前。";
      List<String> wordList = SensitiveWordHelper.findAll(text);
      Assert.assertEquals("[五星红旗, 毛主席, 天安门]", wordList.toString());
      复制代码

      默认的替换策略

      final String text = "五星红旗迎风飘扬,毛主席的画像屹立在天安门前。";
      String result = SensitiveWordHelper.replace(text);
      Assert.assertEquals("****迎风飘扬,***的画像屹立在***前。", result);
      复制代码

      指定替换的内容

      final String text = "五星红旗迎风飘扬,毛主席的画像屹立在天安门前。";
      String result = SensitiveWordHelper.replace(text, '0');
      Assert.assertEquals("0000迎风飘扬,000的画像屹立在000前。", result);
      复制代码

      更多特性

      后续的诸多特性,主要是针对各种针对各种情况的处理,尽可能的提升敏感词命中率。

      这是一场漫长的攻防之战。

      忽略大小写

      final String text = "fuCK the bad words.";
      String word = SensitiveWordHelper.findFirst(text);
      Assert.assertEquals("fuCK", word);
      复制代码

      忽略半角圆角

      final String text = "fuck the bad words.";
      String word = SensitiveWordHelper.findFirst(text);
      Assert.assertEquals("fuck", word);
      复制代码

      忽略数字的写法

      这里实现了数字常见形式的转换。

      final String text = "这个是我的微信:9⓿二肆⁹₈③⑸⒋➃㈤㊄";
      List<String> wordList = SensitiveWordHelper.findAll(text);
      Assert.assertEquals("[9⓿二肆⁹₈③⑸⒋➃㈤㊄]", wordList.toString());
      复制代码

      忽略繁简体

      final String text = "我爱我的祖国和五星紅旗。";
      List<String> wordList = SensitiveWordHelper.findAll(text);
      Assert.assertEquals("[五星紅旗]", wordList.toString());
      复制代码

      忽略英文的书写格式

      final String text = "Ⓕⓤc⒦ the bad words";
      List<String> wordList = SensitiveWordHelper.findAll(text);
      Assert.assertEquals("[Ⓕⓤc⒦]", wordList.toString());
      复制代码

      忽略重复词

      final String text = "ⒻⒻⒻfⓤuⓤ⒰cⓒ⒦ the bad words";
      List<String> wordList = SensitiveWordHelper.findAll(text);
      Assert.assertEquals("[ⒻⒻⒻfⓤuⓤ⒰cⓒ⒦]", wordList.toString());
      复制代码

      邮箱检测

      final String text = "楼主好人,邮箱 sensitiveword@xx.com";
      List<String> wordList = SensitiveWordHelper.findAll(text);
      Assert.assertEquals("[sensitiveword@xx.com]", wordList.toString());
      复制代码

      特性配置

      说明

      上面的特性默认都是开启的,有时业务需要灵活定义相关的配置特性。

      所以 v0.0.14 开放了属性配置。

      配置方法

      为了让使用更加优雅,统一使用 fluent-api 的方式定义。

      用户可以使用 SensitiveWordBs 进行如下定义:

      SensitiveWordBs wordBs = SensitiveWordBs.newInstance()
      .ignoreCase(true)
      .ignoreWidth(true)
      .ignoreNumStyle(true)
      .ignoreChineseStyle(true)
      .ignoreEnglishStyle(true)
      .ignoreRepeat(true)
      .enableNumCheck(true)
      .enableEmailCheck(true)
      .enableUrlCheck(true)
      .init();
      final String text = "五星红旗迎风飘扬,毛主席的画像屹立在天安门前。";
      Assert.assertTrue(wordBs.contains(text));
      复制代码

      配置说明

      其中各项配置的说明如下:

      序号 方法 说明
      1 ignoreCase 忽略大小写
      2 ignoreWidth 忽略半角圆角
      3 ignoreNumStyle 忽略数字的写法
      4 ignoreChineseStyle 忽略中文的书写格式
      5 ignoreEnglishStyle 忽略英文的书写格式
      6 ignoreRepeat 忽略重复词
      7 enableNumCheck 是否启用数字检测。默认连续 8 位数字认为是敏感词
      8 enableEmailCheck 是有启用邮箱检测
      9 enableUrlCheck 是否启用链接检测

      动态加载(用户自定义)

      情景说明

      有时候我们希望将敏感词的加载设计成动态的,比如控台修改,然后可以实时生效。

      v0.0.13 支持了这种特性。

      接口说明

      为了实现这个特性,并且兼容以前的功能,我们定义了两个接口。

      IWordDeny

      接口如下,可以自定义自己的实现。

      返回的列表,表示这个词是一个敏感词。

      /**
      * 拒绝出现的数据-返回的内容被当做是敏感词
      * @author binbin.hou
      * @since 0.0.13
      */
      public interface IWordDeny {
      /**
      * 获取结果
      * @return 结果
      * @since 0.0.13
      */
      List<String> deny();
      }
      复制代码

      比如:

      public class MyWordDeny implements IWordDeny {
      @Override
      public List<String> deny() {
      return Arrays.asList("我的自定义敏感词");
      }
      }
      复制代码

      IWordAllow

      接口如下,可以自定义自己的实现。

      返回的列表,表示这个词不是一个敏感词。

      /**
      * 允许的内容-返回的内容不被当做敏感词
      * @author binbin.hou
      * @since 0.0.13
      */
      public interface IWordAllow {
      /**
      * 获取结果
      * @return 结果
      * @since 0.0.13
      */
      List<String> allow();
      }
      复制代码

      如:

      public class MyWordAllow implements IWordAllow {
      @Override
      public List<String> allow() {
      return Arrays.asList("五星红旗");
      }
      }
      复制代码

      配置使用

      接口自定义之后,当然需要指定才能生效。

      为了让使用更加优雅,我们设计了引导类 SensitiveWordBs

      可以通过 wordDeny() 指定敏感词,wordAllow() 指定非敏感词,通过 init() 初始化敏感词字典。

      系统的默认配置

      SensitiveWordBs wordBs = SensitiveWordBs.newInstance()
      .wordDeny(WordDenys.system())
      .wordAllow(WordAllows.system())
      .init();
      final String text = "五星红旗迎风飘扬,毛主席的画像屹立在天安门前。";
      Assert.assertTrue(wordBs.contains(text));
      复制代码

      备注:init() 对于敏感词 DFA 的构建是比较耗时的,一般建议在应用初始化的时候只初始化一次。而不是重复初始化!

      指定自己的实现

      我们可以测试一下自定义的实现,如下:

      String text = "这是一个测试,我的自定义敏感词。";
      SensitiveWordBs wordBs = SensitiveWordBs.newInstance()
      .wordDeny(new MyWordDeny())
      .wordAllow(new MyWordAllow())
      .init();
      Assert.assertEquals("[我的自定义敏感词]", wordBs.findAll(text).toString());
      复制代码

      这里只有 我的自定义敏感词 是敏感词,而 测试 不是敏感词。

      当然,这里是全部使用我们自定义的实现,一般建议使用系统的默认配置+自定义配置。

      可以使用下面的方式。

      同时配置多个

      • 多个敏感词

      WordDenys.chains() 方法,将多个实现合并为同一个 IWordDeny。

      • 多个白名单

      WordAllows.chains() 方法,将多个实现合并为同一个 IWordAllow。

      例子:

      String text = "这是一个测试。我的自定义敏感词。";
      IWordDeny wordDeny = WordDenys.chains(WordDenys.system(), new MyWordDeny());
      IWordAllow wordAllow = WordAllows.chains(WordAllows.system(), new MyWordAllow());
      SensitiveWordBs wordBs = SensitiveWordBs.newInstance()
      .wordDeny(wordDeny)
      .wordAllow(wordAllow)
      .init();
      Assert.assertEquals("[我的自定义敏感词]", wordBs.findAll(text).toString());
      复制代码

      这里都是同时使用了系统默认配置,和自定义的配置。

      spring 整合

      背景

      实际使用中,比如可以在页面配置修改,然后实时生效。

      数据存储在数据库中,下面是一个伪代码的例子,可以参考 SpringSensitiveWordConfig.java

      要求,版本 v0.0.15 及其以上。

      自定义数据源

      简化伪代码如下,数据的源头为数据库。

      MyDdWordAllow 和 MyDdWordDeny 是基于数据库为源头的自定义实现类。

      @Configuration
      public class SpringSensitiveWordConfig {
      @Autowired
      private MyDdWordAllow myDdWordAllow;
      @Autowired
      private MyDdWordDeny myDdWordDeny;
      /**
      * 初始化引导类
      * @return 初始化引导类
      * @since 1.0.0
      */
      @Bean
      public SensitiveWordBs sensitiveWordBs() {
      SensitiveWordBs sensitiveWordBs = SensitiveWordBs.newInstance()
      .wordAllow(WordAllows.chains(WordAllows.system(), myDdWordAllow))
      .wordDeny(myDdWordDeny)
      // 各种其他配置
      .init();
      return sensitiveWordBs;
      }
      }
      复制代码

      敏感词库的初始化较为耗时,建议程序启动时做一次 init 初始化。

      动态变更

      为了保证敏感词修改可以实时生效且保证接口的尽可能简化,此处没有新增 add/remove 的方法。

      而是在调用 sensitiveWordBs.init() 的时候,根据 IWordDeny+IWordAllow 重新构建敏感词库。

      因为初始化可能耗时较长(秒级别),所有优化为 init 未完成时不影响旧的词库功能,完成后以新的为准

      @Component
      public class SensitiveWordService {
      @Autowired
      private SensitiveWordBs sensitiveWordBs;
      /**
      * 更新词库
      *
      * 每次数据库的信息发生变化之后,首先调用更新数据库敏感词库的方法。
      * 如果需要生效,则调用这个方法。
      *
      * 说明:重新初始化不影响旧的方法使用。初始化完成后,会以新的为准。
      */
      public void refresh() {
      // 每次数据库的信息发生变化之后,首先调用更新数据库敏感词库的方法,然后调用这个方法。
      sensitiveWordBs.init();
      }
      }
      复制代码

      如上,你可以在数据库词库发生变更时,需要词库生效,主动触发一次初始化 sensitiveWordBs.init();

      其他使用保持不变,无需重启应用。

      冠希哥微微一笑,想做事,先做人。

      吴X凡绯闻女友小怡同学被骂到清空社交平台?各大平台连敏感词库都没有的吗?

      拓展阅读

      敏感词工具实现思路

      DFA 算法讲解

      敏感词库优化流程

      停止词的思考记录

      小结

      还是那句话,我们用法律捍卫自己,但是绝不允许有些人把所有的事情都娱乐化,以为钱可以买来一切。

      值此百年之际,更不能让先辈的血白流。

      何况是一个三无的加拿大戏子,建议依法处置,然后(ノ`Д)ノ(优美的中国话)
      吴X凡绯闻女友小怡同学被骂到清空社交平台?各大平台连敏感词库都没有的吗?

      请登录之后再进行评论

      登录

      手机阅读天地(APP)

      • 微信公众号
      • 微信小程序
      • 安卓APP
      手机浏览,惊喜多多
      匿名树洞,说我想说!
      问答悬赏,VIP可见!
      密码可见,回复可见!
      即时聊天、群聊互动!
      宠物孵化,赠送礼物!
      动态像框,专属头衔!
      挑战/抽奖,金币送不停!
      赶紧体会下,不会让你失望!
    • 实时动态
    • 签到
    • 做任务
    • 发表内容
    • 偏好设置
    • 到底部
    • 帖子间隔 侧栏位置:
    • 还没有账号?点这里立即注册