Android离线敏感词校验

2019-01-08  本文已影响0人  duyi324

本文资源来自:https://github.com/k5h9999/keywordfilter
作者: k5h9999
说明:基于分词原理修改写的一个过滤敏感词库,可以改成动态,本敏感词收集了4W多个违法词、敏感词、违禁词,几十个矫正词、变异词。

最近做Android项目用到敏感词校验功能,原本想到用在线检测功能,不过太依赖于网络,而且校验服务器也不一定能一直开通,于是想到了找一下离线库。

文章开头的链接是作者为Java写的代码,我稍加修改,将其用到了我的Android项目中。感谢原作者的分享。
下面是步骤:

1.将词库放到项目中

将上述项目文件src\main\resources\META-INF\dic目录中的两个文件:fqc.dicwfc.dic解压缩,放到Android项目的assets资源文件夹中。如果Android项目中没有这个文件夹,在main目录下自己新建即可。

2.修改代码适配Android

作者的原项目中只有两个类,WordFilterKeyWordFilter,其中在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方法的返回值为:

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>")){
        //包含敏感词的操作
    }    
}
上一篇下一篇

猜你喜欢

热点阅读