前言:一直都这样认为“正则表达式是一个很有用的技能”,从一开始的磕磕绊绊的使用和摸索,到后来可以得心应手,这个过程离不来平时的不断学习和思考🤔。但最近在想正则表达式是如何实现的(即算法),故这几天一直在找相关的博客来学习,慢慢的也大概了解了正则表达式的实现原理。

一:DFA算法

背景>>一个解决查找一些关键词的算法

例如:我要查找一篇文章中,“电影”,“电视”,“电视节目”,“春天”........这个词语出现的次数。

*DFA查找思路

步骤1:遍历该文章中每个字符,并且查看是否含有字符“电”和“春”字符。如果不含有则直接返回false即不含关键字,如果含有(如电)进行步骤2

步骤2:继续查找下一个字符,判断该字符是否是“影”,“视”。如果下一个字符是“影”,这则把电影返回到一个集合中,继续步骤1,直到结束.

*如何通过算法实现DFA算法

1.首先要构建一个关键字的集合(map)

  这个map的特点是,至少有两个值

值1: 记录  关键字(电)=值(又是一个map) //如果是多个值则是关键字是“视”,“影”

值2:记录   状态 =  状态值(是否可以结束)

例如:{电={影={isEnd=1}, 视={节={isEnd=1}, isEnd=0}, isEnd=0}}

Java:实现

private void addSensitiveWordToHashMap(Set<String> keyWordSet) {
        sensitiveWordMap = new HashMap(keyWordSet.size());     //初始化敏感词容器,减少扩容操作
        String key = null;  
        Map nowMap = null;
        Map<String, String> newWorMap = null;
        //迭代keyWordSet
        Iterator<String> iterator = keyWordSet.iterator();
        while(iterator.hasNext()){
            key = iterator.next();    //关键字
            nowMap = sensitiveWordMap;
            for(int i = 0 ; i < key.length() ; i++){
                char keyChar = key.charAt(i);       //转换成char型
                Object wordMap = nowMap.get(keyChar);       //获取
                
                if(wordMap != null){        //如果存在该key,直接赋值
                    nowMap = (Map) wordMap;
                }
                else{     //不存在则,则构建一个map,同时将isEnd设置为0,因为他不是最后一个
                    newWorMap = new HashMap<String,String>();
                    newWorMap.put("isEnd", "0");     //不是最后一个
                    nowMap.put(keyChar, newWorMap);
                    nowMap = newWorMap;
                }
                
                if(i == key.length() - 1){
                    nowMap.put("isEnd", "1");    //最后一个
                }
            }
        }
        System.out.println(sensitiveWordMap.toString());
    }

2.遍历文章的每个字符,

步骤1 :查看该字符在集合中是否存在,如果不存在,则继续查询下一个继续判断步骤1直至结束,如果存在进行步骤2

步骤2:获取该关键字的值的集合,并获取该集合的isEnd属性值,如果为1则表示可以返回并且找到关键字。如果为0则执行步骤3,

步骤3:  获取该关键字的值的集合,并做当前集合。查找下一个字符,并判断该集合中是否存在,如果不存在则返回(表示该关键字查找失败),如果存在循环步骤2

Java实现

@SuppressWarnings({ "rawtypes" })
    public int CheckSensitiveWord(String txt, int beginIndex, int matchType) {
        boolean flag = false; // 敏感词结束标识位:用于敏感词只有1位的情况
        int matchFlag = 0; // 匹配标识数默认为0
        char word = 0;
        Map nowMap = sensitiveWordMap;
        for (int i = beginIndex; i < txt.length(); i++) {
            word = txt.charAt(i);
            nowMap = (Map) nowMap.get(word); // 获取指定key
            if (nowMap != null) { // 存在,则判断是否为最后一个
                matchFlag++; // 找到相应key,匹配标识+1
                if ("1".equals(nowMap.get("isEnd"))) { // 如果为最后一个匹配规则,结束循环,返回匹配标识数
                    flag = true; // 结束标志位为true
                    if (SensitivewordFilter.minMatchTYpe == matchType) { // 最小规则,直接返回,最大规则还需继续查找
                        break;
                    }
                }
            } else { // 不存在,直接返回(查找失败)
                break;
            }
        }
        if (matchFlag < 2 || !flag) { // 长度必须大于等于1,为词
            matchFlag = 0;
        }
        return matchFlag;
    }

编目地址:git:SensitivewordFilter.java和SensitiveWordInit

运行实例:

public static void main(String[] args) {
        SensitivewordFilter filter = new SensitivewordFilter();
        System.out.println("敏感词的数量:" + filter.sensitiveWordMap.size());
        String string = "太多的电视节目";
        System.out.println("待检测语句字数:" + string.length());
        long beginTime = System.currentTimeMillis();
        Set<String> set = filter.getSensitiveWord(string, 2);
        long endTime = System.currentTimeMillis();
        System.out.println("语句中包含敏感词的个数为:" + set.size() + "。包含:" + set);
        System.out.println("总共消耗时间为:" + (endTime - beginTime));
    }


{电={影={isEnd=1}, 视={节={isEnd=1}, isEnd=0}, isEnd=0}, 春={isEnd=1}}
敏感词的数量:2
待检测语句字数:7
语句中包含敏感词的个数为:1。包含:[电视节]
总共消耗时间为:0

 

 

posted on 2019-03-09 00:16  爱我-中华  阅读(548)  评论(0编辑  收藏  举报