1.编辑敏感词文本(.txt)

按行写入
2.编写过滤器
(1)创建前缀树保存敏感词
//前缀树
private class TireNode {
//关键词结束标志
private boolean isKeywordsEnd = false;
//key是下级字符,value是下级节点(root为null)
private Map<Character, TireNode> sonNode = new HashMap<>();
public boolean isKeywordsEnd() {
return isKeywordsEnd;
}
public void setKeywordsEnd(boolean keywordsEnd) {
isKeywordsEnd = keywordsEnd;
}
public void addSonNode(Character val, TireNode son) {
sonNode.put(val, son);
}
public TireNode getSonNode(Character val) {
return sonNode.get(val);
}
}

标志代表是否是word结束,判断时若扫描结束节点非结束标志,则不视为敏感词。
(2)将文本导入
@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) {
this.addKeywords(keyword);
}
} catch (Exception e) {
logger.error("服务器加载敏感词失败" + e.getMessage());
}
}
(3)将敏感词添加到前缀树
//将敏感词添加到前缀树
private void addKeywords(String keyword) {
//指向root
TireNode cur = tireNode;
for (int i = 0; i < keyword.length(); i++) {
//子节点中没有该字符
if (cur.getSonNode(keyword.charAt(i)) == null) {
//新建节点插入
cur.addSonNode(keyword.charAt(i), new TireNode());
}
//指向下一个节点
cur = cur.getSonNode(keyword.charAt(i));
//设置标志位
if (i == keyword.length() - 1) cur.setKeywordsEnd(true);
}
}
(4)过滤敏感词
/**
* 过滤敏感词
*
* @param text 待过滤的敏感词
* @return *****
*/
public String filter(String text) {
if (text == null) return "";
int main = 0, ass = 0;
TireNode cur = tireNode;
StringBuilder builder = new StringBuilder();
while (ass < text.length()) {
char c = text.charAt(ass);
if (isSymbol(c)) {
//如果主指针处于根节点,将此符号计入结果,让副指针继续走
if (cur == tireNode) {
builder.append(c);
main++;
}
//副指针只要碰到符号就后移,主指针只有未开始匹配(树指针为根节点)时碰到符号才后移
ass++;
continue;
}
//寻找当前副指针指向的字符是否在树里
cur = cur.getSonNode(c);
//如果不在将主指针指向的字符压入builder,主指针向后移,树指针指向根节点
if (cur == null) {
builder.append(text.charAt(main));
ass = ++main;
cur = tireNode;
} else if (cur.isKeywordsEnd()) {
//如果副指针指向标志结束处,将代替符号压入builder,主副指针移至副指针后一个
builder.append(REPLACEMENT);
main = ++ass;
cur = tireNode;
} else {
//否则副指针后移继续检查
ass++;
}
}
//将最后一批字符压入
builder.append(text.substring(main));
return builder.toString();
}
//判断是否为特殊符号
private boolean isSymbol(Character c) {
//0x2E80~0x9FFF是东亚文字
//CharUtils.isAsciiAlphanumeric判断是否为特殊符号
return !CharUtils.isAsciiAlphanumeric(c) && (c < 0x2E80 || c > 0x9FFF);
}

- 当走到a时,树指针向下移动到a,副指针继续向后走

- 此时发现结束标记,将abc变为***,树指针指向root
本文介绍了一种基于前缀树的敏感词过滤方法,通过构建前缀树存储敏感词汇,并利用双指针技术进行文本扫描,有效过滤敏感词。文章详细讲解了前缀树节点设计、敏感词添加过程及文本过滤算法。

1800

被折叠的 条评论
为什么被折叠?



