Android离线敏感词校验
本文资源来自:https://github.com/k5h9999/keywordfilter
作者: k5h9999
说明:基于分词原理修改写的一个过滤敏感词库,可以改成动态,本敏感词收集了4W多个违法词、敏感词、违禁词,几十个矫正词、变异词。
最近做Android项目用到敏感词校验功能,原本想到用在线检测功能,不过太依赖于网络,而且校验服务器也不一定能一直开通,于是想到了找一下离线库。
文章开头的链接是作者为Java写的代码,我稍加修改,将其用到了我的Android项目中。感谢原作者的分享。
下面是步骤:
1.将词库放到项目中
将上述项目文件src\main\resources\META-INF\dic
目录中的两个文件:fqc.dic
和wfc.dic
解压缩,放到Android项目的assets
资源文件夹中。如果Android项目中没有这个文件夹,在main
目录下自己新建即可。
2.修改代码适配Android
作者的原项目中只有两个类,WordFilter
和KeyWordFilter
,其中在WordFilter
类中持有对KeyWordFilter
的引用。
我们打开KeyWordFilter
,找到main
方法,查看用法,发现里面有这样的代码:
public static void main(String[] args) {
String str = "一个网站就像一个人,存在一个从小到大白粉的过程。养一个网站和养一个人一样,不同时期漂白粉需要不同的方法,口交--不同的方法下有共24口交换机同的原则。";
Long startTime = System.currentTimeMillis();
WordFilter wf = new WordFilter();
//WordFilter.filter_search(String) 方法是从字符串中删除敏感词后返回结果
System.out.println(wf.filter_search(str));
//WordFilter.filter_jk_info(String)方法是将敏感词标记出来
System.out.println(wf.filter_jk_info("一个网站就像一个人"));
Long endTime = System.currentTimeMillis();
System.out.println("时间:" + (endTime - startTime));
}
我们找到filter_jk_info
方法,查看其实现:
public String filter_jk_info(String content){
return kwf.filter_jk(content,"0","0","<font color=#ff0000>","</font>","<font color=#00ff00>","</font>");
}
再转到filter_jk
方法,发现这里就是核心算法。对比结果发现,此方法是将敏感词用html标签标记为红色和绿色。
我们直接尝试调用会报空指针
异常。跟随异常信息,发现原来是读取词库的时候,数据流报空指针错误:
KeyWordFilter.java
private HashMap<String, String> getWordMap(String dicPath, String replace) {
InputStream is = null;
HashMap<String, String> wordMap = new HashMap<String, String>();
try {
//就是下面这一行返回的is为空
is = KeyWordFilter.class.getResourceAsStream(dicPath);
if (is == null) {
System.out.println(dicPath + " not found!!!");
}
BufferedReader br = new BufferedReader(new InputStreamReader(is,
"UTF-8"), 512);
String theWord = null;
//
// 省略部分代码
//
}
首先将词库文件的全局变量路径修改为:
public static final String PATH_DIC_WFC = "wfc.dic";
public static final String PATH_DIC_FQC = "fqc.dic";
然后将空指针那一行代码改成:
is = App.getContext().getResources().getAssets().open(dicPath);
其中App.getContext()
是自定义Application
中的方法,自己添加即可。
这样就获取到了assets
目录下的文件,并返回了InputStream
。
最后,就可以调用了。
WordFilter mKeywordFilter = new WordFilter();
String s = mKeywordFilter.filter_jk_info2(content);
filter_jk_info2
方法的返回值为:
- 如果没有敏感词,返回原文;
- 如果有敏感词,返回将敏感词标记后的字符串,标记规则在
KeyWordFilter.filter_jk
方法中。
所以,我们可以修改filter_jk_info
方法如下:
public String filter_jk_info(String content) {
return kwf.filter_jk(content, "0", "0", "<mgc>", "</mgc>", "<mgc>", "</mgc>");
}
然后判断返回值s
是否包含<mgc>
标签即可。
总结修改
WordFilter.java
public String filter_jk_info2(String content) {
return kwf.filter_jk(content, "0", "0", "<mgc>", "</mgc>", "<mgc>", "</mgc>");
}
KeyWordFilter.java
public static final String PATH_DIC_WFC = "wfc.dic";
public static final String PATH_DIC_FQC = "fqc.dic";
private HashMap<String, String> getWordMap(String dicPath, String replace) {
InputStream is = null;
HashMap<String, String> wordMap = new HashMap<String, String>();
try {
is = App.getContext().getResources().getAssets().open(dicPath);
if (is == null) {
System.out.println(dicPath + " not found!!!");
}
BufferedReader br = new BufferedReader(new InputStreamReader(is,
"UTF-8"), 512);
String theWord = null;
//
// 省略部分代码
//
}
使用:
private WordFilter mKeywordFilter;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
// 省略部分代码
mKeywordFilter = new WordFilter();
//因为内部是静态对象,所以这里先调用一次生成实例,后面可以加速查找过程,懒得改源码了
new Thread(() -> mKeywordFilter.filter_jk_info2("初始化")).start();
}
public void checkContent(){
String s = mKeywordFilter.filter_jk_info("测试内容");
if(s.contains("<mgc>") || s.contains("</mgc>")){
//包含敏感词的操作
}
}