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