C++ 关键词过滤,屏蔽应用

关键词过滤–延伸多关键词过滤(业务需求)

首先最笨的方法是每个关键词完整的存放在一个容器中,文本内容解析完传过来的时候进行过滤,那么这种方法要对每一个关键词做一次完整比对,不相同则比较下一组,这种最坏的情况为每匹配到一个关键词都要匹配关键词个数的次数。在文本中关键词出现频率较高时,需要检查的文件个数较多时,效率很差。

所以我们把多关键词构建成多叉树结构(即字典树),对于每一个关键词只需要遍历查找一次
(从根节点到终端节点为一个关键词,终端节点中成员key(用来判断是否找到关键词)保存完整的关键词)
在这里插入图片描述

打个比方:关键词为{计算机,软件管家,软件包,软件名称,软件},构建成上图的结构。根节点的map容器中key(map的key)为{软,计} ,每个key对应的value指向下一节点,下面两个节点的map容器中key为别为{件},{算},依次往后。

如果要过滤的的文件中第一个字为’软’或者’计’则继续匹配,看文本中第二个字是否为’件’或者’算’,是继续匹配,每次匹配判断一下当前节点中key(成员变量key)是否为空, key不为空则说明匹配到关键词 ,下一节点不为空则继续匹配。如果不是这’软’或者’计’,则往后移动取文件的第二个字看是不是’软’或者’计’继续匹配

业务应用:点击检查设置,选则关键词点击确定按钮后,会将关键词更新到文件中,然后将文件中的关键词加载到basic_trie类中,使用search检查返回结果(包括了关键词及其位置(相对于文本首部))

在这里插入图片描述

百度了一下这种应该是叫做DFA算法,基于dfa构建多叉树(字典树)

#ifndef OTHERTRIE_HPP
#define OTHERTRIE_HPP

#include <typeinfo>
#include <memory>
#include <string>
#include <map>
#include <queue>

namespace mytrie {

using uchar = unsigned char;
//存储查询到的关键词结果
template<typename CharType>
class result{
public:
    std::basic_string<CharType> sentence;
    unsigned int start;
    unsigned int fin;
public:
    explicit result(){
        start = 0;
        fin = 0;
    }
    explicit result(const std::basic_string<CharType>& sentence, unsigned int start, unsigned int fin):
        sentence(sentence), start(start), fin(fin){}
};

//构建多叉树结构的节点
template<typename CharType>
struct Node{
	//只在一个关键词的最后一个节点保存完整的关键词 用于判断是否找到关键词
    std::basic_string<CharType> key;
	//map中的key保存字节流的一个字节,value指向下一节点
    std::map<uchar, std::unique_ptr<Node<CharType>>> child;
};

template<typename CharType>
class basic_trie{
private:
	//根节点
    std::unique_ptr<Node<CharType>> _root;
    bool module = typeid(uchar).hash_code() == typeid(CharType).hash_code() || typeid(char).hash_code() == typeid(CharType).hash_code();
public:
	//初始化根节点
    basic_trie():_root(new Node<CharType>()){}

	//插入关键字 
    void insert(const std::basic_string<CharType>& key)
	{
        Node<CharType>* root = _root.get();
        if(nullptr == root || key.empty())
		{
            return ;
        }

        int len;
        if(module)
		{
            len = key.size();
        } 
		else 
		{
            len = key.size() * sizeof(CharType);
        }
		//关键词转为字节流
        uchar* p = reinterpret_cast<uchar*>(const_cast<CharType*>(key.c_str()));
        bool flag = false;
		//一次插入形成一个分支  再次插入(调用insert)关键词形成多叉树结构
        for(auto i = 0; i < len; ++i, ++p)
		{
            if(!root->child[*p])
			{
                root->child[*p] = std::unique_ptr<Node<CharType>>(new Node<CharType>());
                flag = true;
            }
            root = root->child[*p].get();
        }
		//一个关键词链的终端节点保存完整的关键词
        if(flag)
		{
            root->key = key;
        }
        return ;
    }

	//下一节点不为空则继续匹配 key不为空则说明匹配到关键词 
    std::vector<result<CharType>> search(const std::basic_string<CharType>& content)			    
    {
        Node<CharType>* node = _root.get();
        if(nullptr == node || content.empty())
        {
            return std::vector<result<CharType>>();
        }

        int len;
        if(module){
            len = content.size();
        } else {
            len = content.size() * sizeof(CharType);
        }

        uchar* p = reinterpret_cast<uchar*>(const_cast<CharType*>(content.c_str()));
        std::vector<result<CharType>> res;

        int i = 0;
        int skipNum = 0;
        while(i < len)
		{
			//过滤关键词中间有空格特殊字符等情况 如:"秘 密" 而不是"秘密"
            while ((i < len) && (*p <= 0x20))
			{
                ++i;
                ++p;
                ++skipNum;
            }

            if(node->child[*p])
			{
				//before the root match, skipNum reset 0
                if(node == _root.get())
                    skipNum = 0;
                Node<CharType>* temp = node->child[*p].get();
                if(!temp->key.empty())
				{
                    res.emplace_back(result<CharType>(temp->key, i + 1 - skipNum - temp->key.size() * sizeof(CharType), i));
                }
                node = node->child[*p].get();
			}
			else
			{
                skipNum = 0;
                node = _root.get();
            }
            ++p;
            ++i;
        }
        return res;
    }
};

}

#endif // OTHERTRIE_HPP
posted @ 2022-09-29 19:40  J1nu  阅读(116)  评论(0)    收藏  举报