美文网首页
Android离线敏感词校验

Android离线敏感词校验

作者: duyi324 | 来源:发表于2019-01-08 17:19 被阅读0次

    本文资源来自: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方法的返回值为:

    • 如果没有敏感词,返回原文;
    • 如果有敏感词,返回将敏感词标记后的字符串,标记规则在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>")){
            //包含敏感词的操作
        }    
    }
    

    相关文章

      网友评论

          本文标题:Android离线敏感词校验

          本文链接:https://www.haomeiwen.com/subject/hkkbrqtx.html