基于Java語言開發(fā)的一個高效的敏感詞過濾工具
基于JAVA語言開發(fā)的一個高效的敏感詞過濾工具
經(jīng)實測,敏感詞數(shù)量為5000個,待檢測文本長度為200時,此工具類可毫秒級高效檢索敏感詞
完整代碼
package com.wgh.common.utils; import com.google.common.collect.Lists; import java.util.*; /** * @desc 一個用于敏感詞檢測的高效工具類 * @author 王冠華 * @date 2024-07-17 */ public class SensitiveWordFilter { private static class TrieNode { Map<Character, TrieNode> children; // 使用 Map 來存儲子節(jié)點 TrieNode fail; // 失敗指針 boolean isEndOfWord; // 標記是否是敏感詞的結(jié)尾 String word; // 存儲完整的敏感詞 public TrieNode() { this.children = new HashMap<>(); // 使用 HashMap 存儲子節(jié)點 this.fail = null; this.isEndOfWord = false; this.word = null; } } private TrieNode root; /** * 構(gòu)造函數(shù),用于初始化敏感詞庫。 * @param words 敏感詞集合,集合確保敏感詞不會重復 */ public SensitiveWordFilter(Set<String> words) { root = new TrieNode(); addWords(words); buildFailurePointers(); } /** * 將敏感詞集合添加到 Trie 樹中。 * @param words 敏感詞集合 */ private void addWords(Set<String> words) { for (String word : words) { addWord(word.toLowerCase()); // 轉(zhuǎn)換為小寫 } } /** * 將單個敏感詞添加到 Trie 樹中。 * @param word 敏感詞 */ private void addWord(String word) { TrieNode current = root; for (char c : word.toCharArray()) { current.children.putIfAbsent(c, new TrieNode()); current = current.children.get(c); } current.isEndOfWord = true; // 標記敏感詞的結(jié)尾 current.word = word; // 存儲完整的敏感詞 } /** * 構(gòu)建失敗指針,用于加速匹配過程。 */ private void buildFailurePointers() { Queue<TrieNode> queue = new LinkedList<>(); root.fail = null; // 根節(jié)點的失敗指針應為 null queue.add(root); while (!queue.isEmpty()) { TrieNode current = queue.poll(); for (Map.Entry<Character, TrieNode> entry : current.children.entrySet()) { char c = entry.getKey(); TrieNode child = entry.getValue(); TrieNode fail = current.fail; while (fail != null && !fail.children.containsKey(c)) { fail = fail.fail; } if (fail == null) { child.fail = root; } else { child.fail = fail.children.get(c); } queue.add(child); } } } /** * 檢查文本中是否包含敏感詞,并返回 true 或 false。 * @param text 要檢查的文本 * @return 如果包含敏感詞,返回 true;否則返回 false */ public boolean containsSensitiveWord(String text) { TrieNode current = root; TrieNode node; for (int i = 0; i < text.length(); i++) { node = current; for (int j = i; j < text.length(); j++) { char c = Character.toLowerCase(text.charAt(j)); // 轉(zhuǎn)換為小寫 while (node != null && !node.children.containsKey(c)) { node = node.fail; // 使用失敗指針進行跳轉(zhuǎn) } if (node == null) { break; } else { node = node.children.get(c); // 跳轉(zhuǎn)到匹配的子節(jié)點 } // 直接在當前節(jié)點判斷是否為敏感詞結(jié)尾 if (node != null && node.isEndOfWord) { return true; } } } return false; // 未找到敏感詞 } /** * 檢查文本中是否包含敏感詞,并返回命中的第一個敏感詞及其位置。 * @param text 要檢查的文本 * @return 包含敏感詞及其位置的 Map.Entry 對象 */ public Map.Entry<String, Integer> findSensitiveWord(String text) { TrieNode current = root; TrieNode node; for (int i = 0; i < text.length(); i++) { node = current; for (int j = i; j < text.length(); j++) { char c = Character.toLowerCase(text.charAt(j)); // 轉(zhuǎn)換為小寫 while (node != null && !node.children.containsKey(c)) { node = node.fail; // 使用失敗指針進行跳轉(zhuǎn) } if (node == null) { break; } else { node = node.children.get(c); // 跳轉(zhuǎn)到匹配的子節(jié)點 } // 直接在當前節(jié)點判斷是否為敏感詞結(jié)尾 if (node != null && node.isEndOfWord) { return new AbstractMap.SimpleEntry<>(node.word, i); } } } return null; // 未找到敏感詞 } /** * 檢查文本中是否包含敏感詞,并返回所有命中的敏感詞及其位置。 * @param text 要檢查的文本 * @return 包含敏感詞及其位置的列表 */ public List<Map.Entry<String, Integer>> findAllSensitiveWords(String text) { List<Map.Entry<String, Integer>> result = new ArrayList<>(); TrieNode current = root; TrieNode node; for (int i = 0; i < text.length(); i++) { node = current; for (int j = i; j < text.length(); j++) { char c = Character.toLowerCase(text.charAt(j)); // 轉(zhuǎn)換為小寫 while (node != null && !node.children.containsKey(c)) { node = node.fail; // 使用失敗指針進行跳轉(zhuǎn) } if (node == null) { break; } else { node = node.children.get(c); // 跳轉(zhuǎn)到匹配的子節(jié)點 } // 直接在當前節(jié)點判斷是否為敏感詞結(jié)尾 if (node != null && node.isEndOfWord) { result.add(new AbstractMap.SimpleEntry<>(node.word, i)); // Continue searching in this segment to find all overlapping sensitive words } } } return result; // 返回所有找到的敏感詞 } public static void main(String[] args) { // 初始化含有5000個敏感詞的HashSet ArrayList<String> list = Lists.newArrayList("敏感詞1","敏感詞2","敏感詞3")); Set<String> set = new HashSet<>(list); // 創(chuàng)建 SensitiveWordFilter 對象 SensitiveWordFilter filter = new SensitiveWordFilter(set); // 要檢查的文本 String text1 = "位于固原市原州區(qū)開城鎮(zhèn)的中莊水庫,敏感詞1是寧夏中南部城鄉(xiāng)敏感詞2飲水安全工程的主敏感詞3調(diào)節(jié)水庫"; String text2 = "位于固原市原州區(qū)開城鎮(zhèn)的中莊水庫,是寧夏中南部城鄉(xiāng)飲水安全工程的主調(diào)節(jié)水庫"; // 使用過濾器進行檢查 boolean containsSensitiveWord1 = filter.containsSensitiveWord(text1); boolean containsSensitiveWord2 = filter.containsSensitiveWord(text2); System.out.println("檢測結(jié)果1: " + containsSensitiveWord1); // true System.out.println("檢測結(jié)果2: " + containsSensitiveWord2); // false Map.Entry<String, Integer> sensitiveWord1 = filter.findSensitiveWord(text1); Map.Entry<String, Integer> sensitiveWord2 = filter.findSensitiveWord(text2); System.out.println("查找結(jié)果1: " + sensitiveWord1); // true System.out.println("查找結(jié)果2: " + sensitiveWord2); // false List<Map.Entry<String, Integer>> allSensitiveWords = filter.findAllSensitiveWords(text1); System.out.println("查找所有結(jié)果: " + allSensitiveWords); } }
方法補充
除了上文的方法,小編還為大家整理了一些其他敏感詞過濾方法,希望對大家有所幫助
方法一:java過濾器實現(xiàn)敏感詞匯過濾
過濾器類
package web.filter; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.ArrayList; import java.util.List; /** * 敏感詞匯過濾器 */ @WebFilter("/*") public class SensitiveWordsFilter implements Filter { public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException { //1.創(chuàng)建代理對象,增強getParameter方法 ServletRequest proxy_req = (ServletRequest) Proxy.newProxyInstance(req.getClass().getClassLoader(), req.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //增強getParameter方法 //判斷是否是getParameter方法 if(method.getName().equals("getParameter")){ //增強返回值 //獲取返回值 String value = (String) method.invoke(req,args); System.out.println("method:"+method.getName()); if(value != null){ for (String str : list) { if(value.contains(str)){ value = value.replaceAll(str,"***"); } } } return value; } //判斷方法名是否是 getParameterMap //判斷方法名是否是 getParameterValue return method.invoke(req,args); } }); //2.放行 chain.doFilter(proxy_req, resp); } private List<String> list = new ArrayList<String>();//敏感詞匯集合 public void init(FilterConfig config) throws ServletException { try{ //1.獲取文件真實路徑 ServletContext servletContext = config.getServletContext(); String realPath = servletContext.getRealPath("/WEB-INF/classes/敏感詞匯.txt"); //2.讀取文件 BufferedReader br = new BufferedReader(new FileReader(realPath)); //3.將文件的每一行數(shù)據(jù)添加到list中 String line = null; while((line = br.readLine())!=null){ list.add(line); } br.close(); System.out.println(list); }catch (Exception e){ e.printStackTrace(); } } public void destroy() { } }
測試類
package web.servlet; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @WebServlet("/testServlet") public class TestServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String name = request.getParameter("name"); String msg = request.getParameter("msg"); System.out.println(name+":"+msg); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } }
方法二:Java敏感詞過濾工具類
import java.util.*; public class SensitiveWordUtil { /** * 敏感詞匹配規(guī)則 */ public static final int MinMatchTYpe = 1; //最小匹配規(guī)則,如:敏感詞庫["中國","中國人"],語句:"我是中國人",匹配結(jié)果:我是[中國]人 public static final int MaxMatchType = 2; //最大匹配規(guī)則,如:敏感詞庫["中國","中國人"],語句:"我是中國人",匹配結(jié)果:我是[中國人] /** * 敏感詞集合 */ public static HashMap sensitiveWordMap; /** * 初始化敏感詞庫,構(gòu)建DFA算法模型 * * @param sensitiveWordSet 敏感詞庫 */ public static synchronized void init(Set<String> sensitiveWordSet) { initSensitiveWordMap(sensitiveWordSet); } /** * 初始化敏感詞庫,構(gòu)建DFA算法模型 * * @param sensitiveWordSet 敏感詞庫 */ private static void initSensitiveWordMap(Set<String> sensitiveWordSet) { //初始化敏感詞容器,減小擴容操做 sensitiveWordMap = new HashMap(sensitiveWordSet.size()); String key; Map nowMap; Map<String, String> newWorMap; //迭代sensitiveWordSet Iterator<String> iterator = sensitiveWordSet.iterator(); while (iterator.hasNext()) { //關鍵字 key = iterator.next(); nowMap = sensitiveWordMap; for (int i = 0; i < key.length(); i++) { //轉(zhuǎn)換成char型 char keyChar = key.charAt(i); //庫中獲取關鍵字 Object wordMap = nowMap.get(keyChar); //若是存在該key,直接賦值,用于下一個循環(huán)獲取 if (wordMap != null) { nowMap = (Map) wordMap; } else { //不存在則,則構(gòu)建一個map,同時將isEnd設置為0,由于他不是最后一個 newWorMap = new HashMap<>(); //不是最后一個 newWorMap.put("isEnd", "0"); nowMap.put(keyChar, newWorMap); nowMap = newWorMap; } if (i == key.length() - 1) { //最后一個 nowMap.put("isEnd", "1"); } } } } /** * 判斷文字是否包含敏感字符 * * @param txt 文字 * @param matchType 匹配規(guī)則 1:最小匹配規(guī)則,2:最大匹配規(guī)則 * @return 若包含返回true,不然返回false */ public static boolean contains(String txt, int matchType) { boolean flag = false; for (int i = 0; i < txt.length(); i++) { int matchFlag = checkSensitiveWord(txt, i, matchType); //判斷是否包含敏感字符 if (matchFlag > 0) { //大于0存在,返回true flag = true; } } return flag; } /** * 判斷文字是否包含敏感字符 * * @param txt 文字 * @return 若包含返回true,不然返回false */ public static boolean contains(String txt) { return contains(txt, MaxMatchType); } /** * 獲取文字中的敏感詞 * * @param txt 文字 * @param matchType 匹配規(guī)則 1:最小匹配規(guī)則,2:最大匹配規(guī)則 * @return */ public static Set<String> getSensitiveWord(String txt, int matchType) { Set<String> sensitiveWordList = new HashSet<>(); for (int i = 0; i < txt.length(); i++) { //判斷是否包含敏感字符 int length = checkSensitiveWord(txt, i, matchType); if (length > 0) {//存在,加入list中 sensitiveWordList.add(txt.substring(i, i + length)); i = i + length - 1;//減1的緣由,是由于for會自增 } } return sensitiveWordList; } /** * 獲取文字中的敏感詞 * * @param txt 文字 * @return */ public static Set<String> getSensitiveWord(String txt) { return getSensitiveWord(txt, MaxMatchType); } /** * 替換敏感字字符 * * @param txt 文本 * @param replaceChar 替換的字符,匹配的敏感詞以字符逐個替換,如 語句:我愛中國人 敏感詞:中國人,替換字符:*, 替換結(jié)果:我愛*** * @param matchType 敏感詞匹配規(guī)則 * @return */ public static String replaceSensitiveWord(String txt, char replaceChar, int matchType) { String resultTxt = txt; //獲取全部的敏感詞 Set<String> set = getSensitiveWord(txt, matchType); Iterator<String> iterator = set.iterator(); String word; String replaceString; while (iterator.hasNext()) { word = iterator.next(); replaceString = getReplaceChars(replaceChar, word.length()); resultTxt = resultTxt.replaceAll(word, replaceString); } return resultTxt; } /** * 替換敏感字字符 * * @param txt 文本 * @param replaceChar 替換的字符,匹配的敏感詞以字符逐個替換,如 語句:我愛中國人 敏感詞:中國人,替換字符:*, 替換結(jié)果:我愛*** * @return */ public static String replaceSensitiveWord(String txt, char replaceChar) { return replaceSensitiveWord(txt, replaceChar, MaxMatchType); } /** * 替換敏感字字符 * * @param txt 文本 * @param replaceStr 替換的字符串,匹配的敏感詞以字符逐個替換,如 語句:我愛中國人 敏感詞:中國人,替換字符串:[屏蔽],替換結(jié)果:我愛[屏蔽] * @param matchType 敏感詞匹配規(guī)則 * @return */ public static String replaceSensitiveWord(String txt, String replaceStr, int matchType) { String resultTxt = txt; //獲取全部的敏感詞 Set<String> set = getSensitiveWord(txt, matchType); Iterator<String> iterator = set.iterator(); String word; while (iterator.hasNext()) { word = iterator.next(); resultTxt = resultTxt.replaceAll(word, replaceStr); } return resultTxt; } /** * 替換敏感字字符 * * @param txt 文本 * @param replaceStr 替換的字符串,匹配的敏感詞以字符逐個替換,如 語句:我愛中國人 敏感詞:中國人,替換字符串:[屏蔽],替換結(jié)果:我愛[屏蔽] * @return */ public static String replaceSensitiveWord(String txt, String replaceStr) { return replaceSensitiveWord(txt, replaceStr, MaxMatchType); } /** * 獲取替換字符串 * * @param replaceChar * @param length * @return */ private static String getReplaceChars(char replaceChar, int length) { String resultReplace = String.valueOf(replaceChar); for (int i = 1; i < length; i++) { resultReplace += replaceChar; } return resultReplace; } /** * 檢查文字中是否包含敏感字符,檢查規(guī)則以下:<br> * * @param txt * @param beginIndex * @param matchType * @return 若是存在,則返回敏感詞字符的長度,不存在返回0 */ private static int checkSensitiveWord(String txt, int beginIndex, int matchType) { //敏感詞結(jié)束標識位:用于敏感詞只有1位的狀況 boolean flag = false; //匹配標識數(shù)默認為0 int matchFlag = 0; char word; Map nowMap = sensitiveWordMap; for (int i = beginIndex; i < txt.length(); i++) { word = txt.charAt(i); //獲取指定key nowMap = (Map) nowMap.get(word); if (nowMap != null) {//存在,則判斷是否為最后一個 //找到相應key,匹配標識+1 matchFlag++; //若是為最后一個匹配規(guī)則,結(jié)束循環(huán),返回匹配標識數(shù) if ("1".equals(nowMap.get("isEnd"))) { //結(jié)束標志位為true flag = true; //最小規(guī)則,直接返回,最大規(guī)則還需繼續(xù)查找 if (MinMatchTYpe == matchType) { break; } } } else {//不存在,直接返回 break; } } if (matchFlag < 2 || !flag) {//長度必須大于等于1,為詞 matchFlag = 0; } return matchFlag; } public static void main(String[] args) { Set<String> sensitiveWordSet = new HashSet<>(); sensitiveWordSet.add("成人電影"); sensitiveWordSet.add("愛戀"); sensitiveWordSet.add("靜靜"); sensitiveWordSet.add("哈哈"); sensitiveWordSet.add("啦啦"); sensitiveWordSet.add("感動"); sensitiveWordSet.add("發(fā)呆"); //初始化敏感詞庫 SensitiveWordUtil.init(sensitiveWordSet); System.out.println("敏感詞的數(shù)量:" + SensitiveWordUtil.sensitiveWordMap.size()); String string = "成人太多的傷感情懷也許只局限于飼養(yǎng)基地 熒幕中的情節(jié)。" + "而后咱們的扮演的角色就是跟隨著主人公的喜紅客聯(lián)盟 怒哀樂而過于牽強的把本身的情感也附加于銀幕情節(jié)中,而后感動就流淚," + "難過就躺在某一我的的懷里盡情的闡述心扉或者手機卡復制器一個賤人一杯紅酒一部電影在夜 深人靜的晚上,關上電話靜靜的發(fā)呆著。"; System.out.println("待檢測語句字數(shù):" + string.length()); //是否含有關鍵字 boolean result = SensitiveWordUtil.contains(string); System.out.println(result); result = SensitiveWordUtil.contains(string, SensitiveWordUtil.MinMatchTYpe); System.out.println(result); //獲取語句中的敏感詞 Set<String> set = SensitiveWordUtil.getSensitiveWord(string); System.out.println("語句中包含敏感詞的個數(shù)為:" + set.size() + "。包含:" + set); set = SensitiveWordUtil.getSensitiveWord(string, SensitiveWordUtil.MinMatchTYpe); System.out.println("語句中包含敏感詞的個數(shù)為:" + set.size() + "。包含:" + set); //替換語句中的敏感詞 String filterStr = SensitiveWordUtil.replaceSensitiveWord(string, '*'); System.out.println(filterStr); filterStr = SensitiveWordUtil.replaceSensitiveWord(string, '*', SensitiveWordUtil.MinMatchTYpe); System.out.println(filterStr); String filterStr2 = SensitiveWordUtil.replaceSensitiveWord(string, "[*敏感詞*]"); System.out.println(filterStr2); filterStr2 = SensitiveWordUtil.replaceSensitiveWord(string, "[*敏感詞*]", SensitiveWordUtil.MinMatchTYpe); System.out.println(filterStr2); } }
到此這篇關于基于Java語言開發(fā)的一個高效的敏感詞過濾工具的文章就介紹到這了,更多相關Java敏感詞過濾內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
JAVA中調(diào)用C語言函數(shù)的實現(xiàn)方式
這篇文章主要介紹了JAVA中調(diào)用C語言函數(shù)的實現(xiàn)方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-08-08java-jsp springmvc-controller 傳值到頁面的方法
下面小編就為大家分享一篇java-jsp springmvc-controller 傳值到頁面的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-03-03不使用Math.random方法生成隨機數(shù)(隨機數(shù)生成器)
不調(diào)用Math.random方法產(chǎn)生自己的隨機數(shù),現(xiàn)代計算機運行速度很快,在主線程等待一定毫秒數(shù)時,其他線程就會執(zhí)行run方法中的while循環(huán),一般會執(zhí)行數(shù)十萬次2014-01-01JAVA使用POI(XSSFWORKBOOK)讀取EXCEL文件過程解析
這篇文章主要介紹了JAVA使用POI(XSSFWORKBOOK)讀取EXCEL文件過程解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2019-08-08