浅析敏感词过滤算法(C++)

为了提高查找效率,这里将敏感词用树形结构存储,每个节点有一个map成员,其映射关系为一个string对应一个TreeNode。

STL::map是按照operator<比较判断元素是否相同,以及比较元素的大小,然后选择合适的位置插入到树中。为了提高map的插入及查询效率,可以选用hash_map或unordered_map。关于他们的效率,可以参考http://blog.csdn.net/whizchen/article/details/9286557

下面主要实现了TreeNode类,进行节点的插入以及查询。(这里命名用Trie比较专业)

 1 #include<map>
 2 #include<string>
 3 //#include<unordered_map>
 4 using namespace std;
 5
 6
 7 class Tree;
 8 class TreeNode
 9 {
10     friend class Tree;
11     typedef map<string,TreeNode> _TreeMap;
12     typedef map<string,TreeNode>::iterator _TreeMapIterator;
13 //     typedef unordered_map<string,TreeNode> _TreeMap;
14 //     typedef unordered_map<string,TreeNode>::iterator _TreeMapIterator;
15 private:
16     string m_character;
17     _TreeMap m_map;
18     TreeNode* m_parent;
19 public:
20     TreeNode(string character);
21     TreeNode(){
22         m_character="";
23     };
24     string getCharacter() const;
25     TreeNode* findChild(string& nextCharacter);
26     TreeNode* insertChild(string& nextCharacter);
27
28 };

TreeNode.h

#include <iostream>
#include "TreeNode.h"
using namespace std;

string TreeNode::getCharacter() const
{
    return m_character;
}

TreeNode::TreeNode(string character)
{
    if (character.size() == 2)
        m_character.assign(character);
    else
        cout<<"error";
}

TreeNode* TreeNode::findChild(string& nextCharacter)
{
    _TreeMapIterator TreeMapIt = m_map.find(nextCharacter);    //利用map/unordered_map进行查找
    return (TreeMapIt == m_map.end()) ? NULL :&TreeMapIt->second;
    return NULL;
}

TreeNode* TreeNode::insertChild(string& nextCharacter)
{
    if(!findChild(nextCharacter))    //添加节点,并返回节点位置
    {
        m_map.insert(pair<string, TreeNode>(nextCharacter, TreeNode(nextCharacter)));
        return &(m_map.find(nextCharacter)->second);
    }
     return NULL;
}

TreeNode.cpp

接下来实现这个tree,在建立TreeNode树时,以parent为根节点建立,一开始parent为m_emptyRoot,然后把keyword按照规则添加到树中,假设一开始m_emptyRoot为空,keyword为"敏感词",则会以"敏感词"为一条分支建立成为一颗树枝‘敏‘->‘感‘->‘词‘,此后,若想再添加"敏感度",由于"敏感词"与"敏感度"的前两个字相同,则会在‘敏‘->‘感‘->‘词‘的基础上,从字‘感‘开始新生长出一颗分支,即‘敏‘->‘感‘->‘度‘,这两颗分支共用‘敏‘->‘感‘。

程序中暂时考虑中文的情况,如果需要考虑英文或中英文结合的情况,将PACE改为1,另外程序做出部分修改即可。

下面代码实现了Tree类,进行树的构成及查询。

 1 #include "TreeNode.h"
 2 using namespace std;
 3
 4 class Tree
 5 {
 6 public:
 7     int count;    //当前查找的一个敏感词的字数
 8     TreeNode* insert(string& keyword);
 9     TreeNode* insert(const char* keyword);
10     TreeNode* find(string& keyword);
11     Tree(){
12         count = 0;
13     };
14 private:
15     TreeNode m_emptyRoot;
16     int m_pace;
17     TreeNode* insert(TreeNode* parent, string& keyword);
18     TreeNode* insertBranch(TreeNode* parent, string& keyword);
19     TreeNode* find(TreeNode* parent,string& keyword);
20
21 };

Tree.h

 1 #include "Tree.h"
 2 #include<iostream>
 3
 4 #define PACE 2    //如果需要考虑英文或中英文结合的情况,将PACE改为1,另外程序还需要做部分修改
 5
 6 TreeNode* Tree::insert(string& keyword)
 7 {
 8     return insert(&m_emptyRoot, keyword);
 9 }
10
11 TreeNode* Tree::insert(const char* keyword)
12 {
13     string wordstr(keyword);
14     return insert(wordstr);
15 }
16
17
18 TreeNode* Tree::insert(TreeNode* parent, string& keyword)
19 {
20     if(keyword.size()==0)
21         return NULL;
22     string firstChar=keyword.substr(0,PACE);
23     TreeNode* firstNode = parent->findChild(firstChar);
24     if(firstNode==NULL)
25         return insertBranch(parent,keyword);
26     string restChar=keyword.substr(PACE,keyword.size());
27     return insert(firstNode,restChar);
28 }
29
30 TreeNode* Tree::insertBranch(TreeNode* parent,string& keyword)
31 {
32     string firstChar=keyword.substr(0,PACE);
33     TreeNode* firstNode = parent->insertChild(firstChar);
34     if(firstNode!=NULL)
35     {
36         string restChar=keyword.substr(PACE,keyword.size());
37         if(!restChar.empty())
38             return insertBranch(firstNode,restChar);
39     }
40     return NULL;
41 }
42
43 TreeNode* Tree::find(string& keyword)
44 {
45     return find(&m_emptyRoot,keyword);
46 }
47
48
49 TreeNode* Tree::find(TreeNode* parent,string& keyword)
50 {
51     string firstChar=keyword.substr(0,PACE);
52     TreeNode* firstNode = parent->findChild(firstChar);
53     if(firstNode==NULL)            //未找到
54     {
55         count=0;
56         return NULL;
57     }
58     string restChar=keyword.substr(PACE,keyword.size());
59     if(firstNode->m_map.empty())        //对应词组结束,则判断该词为敏感词
60     {
61         //std::cout<<count+1<<endl;
62         return firstNode;
63     }
64     if(keyword.size()==PACE)    //最后一个字
65         return NULL;
66     count++;
67     return find(firstNode,restChar);
68 }

Tree.cpp

最后就是利用上述的Tree来实现敏感词过滤,Filter::censor(string& source)函数用来进行敏感词过滤,source即输入的字符串,如果source包含敏感词,则用"**"代替掉。

Filter::load(const char* filePath)函数通过文件载入敏感词,并构建Tree。

为使实现简单,代码中过滤了英文数字及一些符号,让敏感词库的词能全部被识别。这里有2个问题遗留下来:

1.需要考虑英文,已经中英文结合的敏感词。程序还需要作出一定修改;

2.载入文件后,可对敏感词做出一定优化。

下面代码实现了Filter类,调用函数实现敏感词过滤。

 1 #include <string>
 2 #include "Tree.h"
 3
 4 class Filter
 5 {
 6 private:
 7     Tree m_tree;
 8
 9 public:
10     void load(const char* fileName);
11     bool m_initialized;
12     void censor(string& source);
13 };

Filter.h

 1 #include <iostream>
 2 #include <fstream>
 3 #include "Filter.h"
 4
 5 void Filter::load(const char* filePath)
 6 {
 7     ifstream keywordsFile(filePath, ios::in);
 8     if (keywordsFile.is_open())
 9     {
10         char buffer[256];
11         int count = 0;
12         int offset = 0;
13         while((buffer[offset]=keywordsFile.get())!=EOF)
14         {
15             if((buffer[offset]>=‘a‘&&buffer[offset]<=‘z‘)||
16                 (buffer[offset]>=‘A‘&&buffer[offset]<=‘Z‘)||
17                 (buffer[offset]>=‘0‘&&buffer[offset]<=‘9‘)||
18                 buffer[offset]==‘\‘‘)
19                 continue;
20             string word1;
21             word1.assign(buffer,offset);
22             if(buffer[offset]==‘,‘&&(offset%2)==0)
23             {
24                 string word;
25                 if(offset)
26                 {
27                     word.assign(buffer,offset);
28                     m_tree.insert(word);
29                 }
30                 offset = 0;
31             }
32             else
33                 offset++;
34         }
35     }
36     keywordsFile.close();
37     m_initialized = true;
38 }
39
40
41 void Filter::censor(string& source)
42 {
43     if (!m_initialized)
44     {
45         cout<<"没有载入关键词";
46         return;
47     }
48     else
49     {
50         int length = source.size();
51         for (int i = 0; i < length; i += 2)
52         {
53             string substring = source.substr(i, length - i);
54             if (m_tree.find(substring) != NULL)    //发现敏感词
55             {
56                 cout<<substring.substr(0,(m_tree.count+1)*2)<<endl;
57                 source.replace(i,(m_tree.count+1)*2,"**");
58                 length = source.size();
59             }
60         }
61     }
62 }

Filter.cpp

最后就是调用Filter类,通过文件输入,并将过滤的结果输出到文件,并输出用时。

 1 #include<iostream>
 2 #include<string>
 3 #include<list>
 4 #include <fstream>
 5 #include "Filter.h"
 6 #include <sys/timeb.h>
 7 using namespace std;
 8
 9 void main()
10 {
11     Filter filter;
12     string str;
13     filter.load("keywords.txt");
14     ifstream inputFile("input.txt",ios::in);
15     inputFile>>str;
16     inputFile.close();
17     ofstream outputFile("output.txt",ios::out);
18     struct timeb startTime,endTime;
19     ftime(&startTime);
20     for(int i=0;i<1000;i++)
21     {
22         filter.censor(str);
23     }
24     ftime(&endTime);
25     cout<<str<<endl;
26     cout<<"查询用时:"<<(endTime.time-startTime.time)*1000 +
27         (endTime.millitm - startTime.millitm)<<"ms"<<endl;
28     outputFile<<str<<endl;
29     outputFile<<"查询用时:"<<(endTime.time-startTime.time)*1000 +
30         (endTime.millitm - startTime.millitm)<<"ms";
31     outputFile.close();
32 }

Process.cpp

浅析敏感词过滤算法(C++)

时间: 2024-08-30 01:48:02

浅析敏感词过滤算法(C++)的相关文章

[Java Web]敏感词过滤算法

1.DFA算法 DFA算法的原理可以参考这里,简单来说就是通过Map构造出一颗敏感词树,树的每一条由根节点到叶子节点的路径构成一个敏感词,例如下图: 代码简单实现如下: public class TextFilterUtil { //日志 private static final Logger LOG = LoggerFactory.getLogger(TextFilterUtil.class); //敏感词库 private static HashMap sensitiveWordMap =

敏感词过滤算法:前缀树算法

背景 平时我们在逛贴吧的时候,我们经常可以看到一些形如 “***”的符号,通过上下文,我们也可以很容易猜到这些词原来是骂人的话,只是被系统和谐了.那么这是如何实现的呢?作为普通人,我们最先想到的一种办法就是把所有敏感串存入一个列表中,然后用户每发一条内容后台就把该内容与敏感串列表的每一项进行匹配,然后把匹配的字符进行和谐.显然这样的效率是很低的.非常影响性能,那么我们有没有其他的算法呢?这就是我这篇博文打算介绍的. 原理讲解 1.首先建立个敏感词前缀树 根节点为空 2.准备好待处理字符串: 哈哈

敏感词过滤的算法原理之DFA算法

参考文档 http://blog.csdn.net/chenssy/article/details/26961957 敏感词.文字过滤是一个网站必不可少的功能,如何设计一个好的.高效的过滤算法是非常有必要的.前段时间我一个朋友(马上毕业,接触编程不久)要我帮他看一个文字过滤的东西,它说检索效率非常慢.我把它程序拿过来一看,整个过程如下:读取敏感词库.如果HashSet集合中,获取页面上传文字,然后进行匹配.我就想这个过程肯定是非常慢的.对于他这个没有接触的人来说我想也只能想到这个,更高级点就是正

java实现敏感词过滤(DFA算法)

小Alan在最近的开发中遇到了敏感词过滤,便去网上查阅了很多敏感词过滤的资料,在这里也和大家分享一下自己的理解. 在写之前,小Alan给大家推荐一篇来自http://cmsblogs.com/?p=1031的博文,也会参考部分内容来描述博文. 敏感词过滤应该是不用给大家过多的解释吧?讲白了就是你在项目中输入某些字(比如输入xxoo相关的文字时)时要能检测出来,很多项目中都会有一个敏感词管理模块,在敏感词管理模块中你可以加入敏感词,然后根据加入的敏感词去过滤输入内容中的敏感词并进行相应的处理,要么

转:Java实现敏感词过滤

敏感词.文字过滤是一个网站必不可少的功能,如何设计一个好的.高效的过滤算法是非常有必要的.前段时间我一个朋友(马上毕业,接触编程不久)要我帮他看一个文字过滤的东西,它说检索效率非常慢.我把它程序拿过来一看,整个过程如下:读取敏感词库.如果HashSet集合中,获取页面上传文字,然后进行匹配.我就想这个过程肯定是非常慢的.对于他这个没有接触的人来说我想也只能想到这个,更高级点就是正则表达式.但是非常遗憾,这两种方法都是不可行的.当然,在我意识里没有我也没有认知到那个算法可以解决问题,但是Googl

Java实现敏感词过滤

敏感词.文字过滤是一个网站必不可少的功能,如何设计一个好的.高效的过滤算法是非常有必要的.前段时间我一个朋友(马上毕业,接触编程不久)要我帮他看一个文字过滤的东西,它说检索效率非常慢.我把它程序拿过来一看,整个过程如下:读取敏感词库.如果HashSet集合中,获取页面上传文字,然后进行匹配.我就想这个过程肯定是非常慢的.对于他这个没有接触的人来说我想也只能想到这个,更高级点就是正则表达式.但是非常遗憾,这两种方法都是不可行的.当然,在我意识里没有我也没有认知到那个算法可以解决问题,但是Googl

Java实现敏感词过滤(转)

敏感词.文字过滤是一个网站必不可少的功能,如何设计一个好的.高效的过滤算法是非常有必要的.前段时间我一个朋友(马上毕业,接触编程不久)要我帮他看一个文字过滤的东西,它说检索效率非常慢.我把它程序拿过来一看,整个过程如下:读取敏感词库.如果HashSet集合中,获取页面上传文字,然后进行匹配.我就想这个过程肯定是非常慢的.对于他这个没有接触的人来说我想也只能想到这个,更高级点就是正则表达式.但是非常遗憾,这两种方法都是不可行的.当然,在我意识里没有我也没有认知到那个算法可以解决问题,但是Googl

敏感词过滤

敏感词过滤是很多网站.论坛常用的功能,一下为相关文章: 1.关于java中敏感词检测的一些总结 2.Java 利用DFA算法 屏蔽敏感词 3.Java实现敏感词过滤--DFA算法

DFA和trie字典树实现敏感词过滤(python和c语言)

现在做的项目都是用python开发,需要用做关键词检查,过滤关键词,之前用c语言做过这样的事情,用字典树,蛮高效的,内存小,检查快. 到了python上,第一想法是在pip上找一个基于c语言的python字典树模块,可惜没找到合适的,如果我会用c写python模块的话,我就自己写一个了,可惜我还不具备这个能力, 只能用python写了,性能差一点就差点吧,内存多一点也无所谓了. 用搜索引擎看CSDN上的网友的用python实现的DFA,再参照自己以前用c语言写过的字典树,有些不大对,就自己写了一