Sfoglia il codice sorgente

feature: add words sensitive filter

ggbocoder 2 anni fa
parent
commit
505e03c9bc

+ 6 - 0
pom.xml

@@ -55,6 +55,12 @@
             <groupId>jakarta.mail</groupId>
             <artifactId>jakarta.mail-api</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+            <version>3.12.0</version> <!-- 使用最新版本 -->
+        </dependency>
+
 
         <dependency>
             <groupId>io.jsonwebtoken</groupId>

+ 134 - 0
src/main/java/cn/seecoder/fdroidrepository/security/SensitiveFilter.java

@@ -0,0 +1,134 @@
+package cn.seecoder.fdroidrepository.security;
+
+import org.apache.commons.lang3.CharUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.PostConstruct;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+
+@Component
+public class SensitiveFilter {
+    private static final Logger logger = LoggerFactory.getLogger(SensitiveFilter.class);
+
+    // sensitive words will be replaced by REPLACE_HOLDER
+    private static final String REPLACE_HOLDER = "***";
+
+    private final TrieNode rootNode = new TrieNode();
+
+    @PostConstruct
+    public void init() {
+        try (
+            InputStream is = this.getClass().getClassLoader().getResourceAsStream("sensitive-words.txt");
+            BufferedReader reader = new BufferedReader(new InputStreamReader(is));
+        ) {
+            String keyword;
+            while ((keyword = reader.readLine()) != null) {
+                addKeyword(keyword);
+            }
+
+        } catch (IOException e) {
+            logger.error("load sensitive words failed: " + e.getMessage());
+        }
+
+    }
+
+    private void addKeyword(String keyword) {
+        TrieNode ptr = rootNode;
+        for (int i = 0; i < keyword.length(); i++) {
+            char c = keyword.charAt(i);
+            TrieNode subNode = ptr.getSubNode(c);
+            if (Objects.isNull(subNode)) {
+                ptr.addSubNode(c, new TrieNode());
+                subNode = ptr.getSubNode(c);
+            }
+            ptr = subNode;
+            if (i == keyword.length() - 1) {
+                ptr.setKeyWordEnd(true);
+            }
+        }
+    }
+
+    /**
+     * @param text raw words before sensitive filter
+     * @return words after sensitive filter
+     */
+    public String filter(String text) {
+        if (StringUtils.isBlank(text)) {
+            return text;
+        }
+        TrieNode ptr = rootNode;
+        int begin = 0, position = 0;
+        StringBuilder sb = new StringBuilder();
+
+        while (begin < text.length()) {
+            char c = text.charAt(position);
+            // handle symbol
+            if (isSymbol(c)) {
+                if (ptr == rootNode) {
+                    sb.append(c);
+                    begin++;
+                }
+                position++;
+                continue;
+            }
+            ptr = ptr.getSubNode(c);
+            if (ptr == null) {
+                sb.append(text.charAt(begin));
+                position=++begin;
+                ptr=rootNode;
+            }else if(ptr.isKeyWordEnd()){
+                sb.append(REPLACE_HOLDER);
+                begin=++position;
+                ptr=rootNode;
+            }else{
+                position++;
+            }
+        }
+        return sb.toString();
+    }
+
+
+    private boolean isSymbol(Character c) {
+
+        return !CharUtils.isAsciiAlphanumeric(c) && (c < 0x2E80 || c > 0x9FFF);
+    }
+
+    private static class TrieNode {
+        private boolean isEnd = false;
+
+        private final Map<Character, TrieNode> subNodes = new HashMap<>();
+
+        public boolean isKeyWordEnd() {
+            return isEnd;
+        }
+
+        public void setKeyWordEnd(boolean keyWordEnd) {
+            isEnd = keyWordEnd;
+        }
+
+        /**
+         * add sub nodes
+         */
+        public void addSubNode(Character c, TrieNode node) {
+            subNodes.put(c, node);
+        }
+
+        /**
+         * get sub nodes
+         */
+        public TrieNode getSubNode(Character c) {
+            return subNodes.get(c);
+        }
+
+
+    }
+}

+ 5 - 0
src/main/resources/sensitive-words.txt

@@ -0,0 +1,5 @@
+赌博
+嫖娼
+吸毒
+开票
+干恁娘

+ 22 - 0
src/test/java/cn/seecoder/fdroidrepository/security/SensitiveFilterTest.java

@@ -0,0 +1,22 @@
+package cn.seecoder.fdroidrepository.security;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+@SpringBootTest
+class SensitiveFilterTest {
+
+    @Autowired
+    private SensitiveFilter sensitiveFilter;
+
+    @Test
+    void filter() {
+        String text1 = "今晚去赌博吗?";
+        String text2 = "干恁娘";
+        Assertions.assertEquals("今晚去***吗?",sensitiveFilter.filter(text1));
+    }
+}