美文网首页
Unity中使用字典树(前缀树)过滤敏感词

Unity中使用字典树(前缀树)过滤敏感词

作者: 雄关漫道从头越 | 来源:发表于2020-09-22 21:34 被阅读0次

利用利用字典树(前缀树)过滤敏感词
【SpringBoot】前缀树 Trie 过滤敏感词

最近在刷leetcode,碰到了字典树(Trie),可以用来最敏感词过滤,于是想到在unity里实现一下,当然,因为使用字典树做敏感词过滤需要比较大的内存,这在Unity前端是不建议这个做的,一般都放在服务器去做过滤,这里主要是学习算法思想。

/////TrieNode.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class TrieNode
{
    /**
     * 标识当前结点是否是一个“关键词”的最后一个结点
     * true 关键词的终结 false 继续
     */
    private bool _isEnd = false;

    /**
     * 用map来存储当前结点的所有子节点,非常的方便
     * key 下一个字符 value 对应的结点
     */
    private Dictionary<char, TrieNode> subNodes = new Dictionary<char, TrieNode>();

    /// <summary>
    /// 向指定位置添加结点树
    /// </summary>
    /// <param name="key"></param>
    /// <param name="node"></param>
    public void AddSubNode(char key, TrieNode node)
    {
        subNodes.Add(key, node);
    }

    /// <summary>
    /// 根据key获得相应的子节点
    /// </summary>
    /// <param name="key"></param>
    /// <returns></returns>
    public TrieNode GetSubNode(char key)
    {
        if (subNodes.ContainsKey(key))
            return subNodes[key];
        return null;
    }

    /// <summary>
    /// 判断是否是关键字的结尾
    /// </summary>
    public bool isKeyWordEnd
    {
        get { return _isEnd; }
        set
        {
            _isEnd = value;
        }
    }
}
////Trie.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

public class Trie
{
    //默认敏感词替换符
    private const String DEFAULT_REPLACEMENT = "敏感词";
    //根节点
    private TrieNode rootNode = new TrieNode();

    /// <summary>
    /// 判断是否是一个符号
    /// </summary>
    /// <param name="c"></param>
    /// <returns></returns>
    private bool IsSymbol(char c)
    {
        int ic = c;
        // 0x2E80-0x9FFF 东亚文字范围
        return !((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) && (ic < 0x2E80 || ic > 0x9FFF);
    }

    /// <summary>
    /// 根据输入的字符串列表构造字典树
    /// </summary>
    /// <param name="words"></param>
    public void AddWords(List<string> words)
    {
        if (words == null || words.Count == 0) return;
        for (int i = 0, count = words.Count; i < count; i++)
        {
            AddWord(words[i]);
        }
    }

    /// <summary>
    ///  根据输入的字符串构造字典树
    /// </summary>
    /// <param name="word"></param>
    public void AddWord(string word)
    {
        if (string.IsNullOrEmpty(word))
            return;
        TrieNode tempNode = rootNode;
        // 循环每个字节
        for (int i = 0; i < word.Length; ++i)
        {
            char c = word[i];
            // 过滤字符
            if (IsSymbol(c))
            {
                continue;
            }
            TrieNode node = tempNode.GetSubNode(c);

            if (node == null)
            { // 没初始化
                node = new TrieNode();
                tempNode.AddSubNode(c, node);
            }

            tempNode = node;

            if (i == word.Length - 1)
            {
                // 关键词结束, 设置结束标志
                tempNode.isKeyWordEnd = true;
            }
        }
    }

    /// <summary>
    /// 过滤敏感词
    /// </summary>
    /// <param name="text"></param>
    /// <returns></returns>
    public string Filter(string text)
    {
        if (string.IsNullOrEmpty(text))
        {
            return text;
        }
        String replacement = DEFAULT_REPLACEMENT;
        StringBuilder result = new StringBuilder();

        TrieNode tempNode = rootNode;
        int begin = 0; // 回滚数
        int position = 0; // 当前比较的位置

        while (position < text.Length)
        {
            char c = text[position];
            // 字符直接跳过
            if (IsSymbol(c))
            {
                if (tempNode == rootNode)
                {
                    result.Append(c);//直接放入结果集
                    ++begin;//起始索引位++
                }
                ++position;//索引++
                continue;
            }

            tempNode = tempNode.GetSubNode(c);

            // 当前位置的匹配结束
            if (tempNode == null)
            {
                // 以begin开始的字符串不存在敏感词
                result.Append(text[begin]);
                // 跳到下一个字符开始测试
                position = begin + 1;
                begin = position;
                // 回到树初始节点
                tempNode = rootNode;
            }
            else if (tempNode.isKeyWordEnd)
            {
                // 发现敏感词, 从begin到position的位置用replacement替换掉
                result.Append(replacement);
                position = position + 1;
                begin = position;
                tempNode = rootNode;
            }
            else
            {
                ++position;
            }
        }

        result.Append(text.Substring(begin));

        return result.ToString();
    }
}
////FilterView .cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class FilterView : MonoBehaviour
{
    public InputField inputField;
    public Text resultTxt;
    private List<string> words;
    private Trie trie;

    void Start()
    {
        trie = new Trie();
        words = new List<string>() { "shit", "傻逼", "笨蛋" };
        trie.AddWords(words);
    }

    #region Event Handler
    public void OnFilterBtnClickHandler()
    {
        string text = trie.Filter(inputField.text);
        Debug.Log("过滤结果:" + text);
        resultTxt.text = text;
    }
    #endregion
}
敏感词过滤

github:https://github.com/eangulee/TrieFilter.git

相关文章

网友评论

      本文标题:Unity中使用字典树(前缀树)过滤敏感词

      本文链接:https://www.haomeiwen.com/subject/jyegyktx.html