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

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

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

 #include<map>
#include<string>
//#include<unordered_map>
using namespace std; class Tree;
class TreeNode
{
friend class Tree;
typedef map<string,TreeNode> _TreeMap;
typedef map<string,TreeNode>::iterator _TreeMapIterator;
// typedef unordered_map<string,TreeNode> _TreeMap;
// typedef unordered_map<string,TreeNode>::iterator _TreeMapIterator;
private:
string m_character;
_TreeMap m_map;
TreeNode* m_parent;
public:
TreeNode(string character);
TreeNode(){
m_character="";
};
string getCharacter() const;
TreeNode* findChild(string& nextCharacter);
TreeNode* insertChild(string& nextCharacter); };

TreeNode.h

#include <iostream>
#include "TreeNode.h"
using namespace std; string TreeNode::getCharacter() const
{
return m_character;
} TreeNode::TreeNode(string character)
{
if (character.size() == )
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类,进行树的构成及查询。

 #include "TreeNode.h"
using namespace std; class Tree
{
public:
int count; //当前查找的一个敏感词的字数
TreeNode* insert(string& keyword);
TreeNode* insert(const char* keyword);
TreeNode* find(string& keyword);
Tree(){
count = ;
};
private:
TreeNode m_emptyRoot;
int m_pace;
TreeNode* insert(TreeNode* parent, string& keyword);
TreeNode* insertBranch(TreeNode* parent, string& keyword);
TreeNode* find(TreeNode* parent,string& keyword); };

Tree.h

 #include "Tree.h"
#include<iostream> #define PACE 2 //如果需要考虑英文或中英文结合的情况,将PACE改为1,另外程序还需要做部分修改 TreeNode* Tree::insert(string& keyword)
{
return insert(&m_emptyRoot, keyword);
} TreeNode* Tree::insert(const char* keyword)
{
string wordstr(keyword);
return insert(wordstr);
} TreeNode* Tree::insert(TreeNode* parent, string& keyword)
{
if(keyword.size()==)
return NULL;
string firstChar=keyword.substr(,PACE);
TreeNode* firstNode = parent->findChild(firstChar);
if(firstNode==NULL)
return insertBranch(parent,keyword);
string restChar=keyword.substr(PACE,keyword.size());
return insert(firstNode,restChar);
} TreeNode* Tree::insertBranch(TreeNode* parent,string& keyword)
{
string firstChar=keyword.substr(,PACE);
TreeNode* firstNode = parent->insertChild(firstChar);
if(firstNode!=NULL)
{
string restChar=keyword.substr(PACE,keyword.size());
if(!restChar.empty())
return insertBranch(firstNode,restChar);
}
return NULL;
} TreeNode* Tree::find(string& keyword)
{
return find(&m_emptyRoot,keyword);
} TreeNode* Tree::find(TreeNode* parent,string& keyword)
{
string firstChar=keyword.substr(,PACE);
TreeNode* firstNode = parent->findChild(firstChar);
if(firstNode==NULL) //未找到
{
count=;
return NULL;
}
string restChar=keyword.substr(PACE,keyword.size());
if(firstNode->m_map.empty()) //对应词组结束,则判断该词为敏感词
{
//std::cout<<count+1<<endl;
return firstNode;
}
if(keyword.size()==PACE) //最后一个字
return NULL;
count++;
return find(firstNode,restChar);
}

Tree.cpp

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

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

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

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

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

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

 #include <string>
#include "Tree.h" class Filter
{
private:
Tree m_tree; public:
void load(const char* fileName);
bool m_initialized;
void censor(string& source);
};

Filter.h

 #include <iostream>
#include <fstream>
#include "Filter.h" void Filter::load(const char* filePath)
{
ifstream keywordsFile(filePath, ios::in);
if (keywordsFile.is_open())
{
char buffer[];
int count = ;
int offset = ;
while((buffer[offset]=keywordsFile.get())!=EOF)
{
if((buffer[offset]>='a'&&buffer[offset]<='z')||
(buffer[offset]>='A'&&buffer[offset]<='Z')||
(buffer[offset]>=''&&buffer[offset]<='')||
buffer[offset]=='\'')
continue;
string word1;
word1.assign(buffer,offset);
if(buffer[offset]==','&&(offset%)==)
{
string word;
if(offset)
{
word.assign(buffer,offset);
m_tree.insert(word);
}
offset = ;
}
else
offset++;
}
}
keywordsFile.close();
m_initialized = true;
} void Filter::censor(string& source)
{
if (!m_initialized)
{
cout<<"没有载入关键词";
return;
}
else
{
int length = source.size();
for (int i = ; i < length; i += )
{
string substring = source.substr(i, length - i);
if (m_tree.find(substring) != NULL) //发现敏感词
{
cout<<substring.substr(,(m_tree.count+)*)<<endl;
source.replace(i,(m_tree.count+)*,"**");
length = source.size();
}
}
}
}

Filter.cpp

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

 #include<iostream>
#include<string>
#include<list>
#include <fstream>
#include "Filter.h"
#include <sys/timeb.h>
using namespace std; void main()
{
Filter filter;
string str;
filter.load("keywords.txt");
ifstream inputFile("input.txt",ios::in);
inputFile>>str;
inputFile.close();
ofstream outputFile("output.txt",ios::out);
struct timeb startTime,endTime;
ftime(&startTime);
for(int i=;i<;i++)
{
filter.censor(str);
}
ftime(&endTime);
cout<<str<<endl;
cout<<"查询用时:"<<(endTime.time-startTime.time)* +
(endTime.millitm - startTime.millitm)<<"ms"<<endl;
outputFile<<str<<endl;
outputFile<<"查询用时:"<<(endTime.time-startTime.time)* +
(endTime.millitm - startTime.millitm)<<"ms";
outputFile.close();
}

Process.cpp

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

  1. 超强敏感词过滤算法第二版 可以忽略大小写、全半角、简繁体、特殊符号、HTML标签干扰

    上一篇 发一个高性能的敏感词过滤算法 可以忽略大小写.全半角.简繁体.特殊符号干扰 改进主要有几点: 用BitArray取代Dictionary用空间换时间 性能进一步提升 大概会增加词库的  6k* ...

  2. 8.2 前端检索的敏感词过滤的Python实现(针对元搜索)

    对于前端的搜索内容进行控制,比如敏感词过滤,同样使用socket,这里使用Python语言做一个demo.这里不得不感叹一句,socket真是太神奇了,可以跨语言把功能封装,为前端提供服务. 下面就是 ...

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

    小Alan在最近的开发中遇到了敏感词过滤,便去网上查阅了很多敏感词过滤的资料,在这里也和大家分享一下自己的理解. 敏感词过滤应该是不用给大家过多的解释吧?讲白了就是你在项目中输入某些字(比如输入xxo ...

  4. Java实现敏感词过滤 - DFA算法

    Java实现DFA算法进行敏感词过滤 封装工具类如下: 使用前需对敏感词库进行初始化: SensitiveWordUtil.init(sensitiveWordSet); package cn.swf ...

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

    参考文档 http://blog.csdn.net/chenssy/article/details/26961957 敏感词.文字过滤是一个网站必不可少的功能,如何设计一个好的.高效的过滤算法是非常有 ...

  6. 基于DFA算法、RegExp对象和vee-validate实现前端敏感词过滤

    面临敏感词过滤的问题,最简单的方案就是对要检测的文本,遍历所有敏感词,逐个检测输入的文本是否包含指定的敏感词. 很明显上面这种实现方法的检测时间会随着敏感词库数量的增加而线性增加.系统会因此面临性能和 ...

  7. Java实现敏感词过滤

    敏感词.文字过滤是一个网站必不可少的功能,如何设计一个好的.高效的过滤算法是非常有必要的.前段时间我一个朋友(马上毕业,接触编程不久)要我帮他看一个文字过滤的东西,它说检索效率非常慢.我把它程序拿过来 ...

  8. 转:鏖战双十一-阿里直播平台面临的技术挑战(webSocket, 敏感词过滤等很不错)

    转自:http://www.infoq.com/cn/articles/alibaba-broadcast-platform-technology-challenges 鏖战双十一-阿里直播平台面临的 ...

  9. java敏感词过滤

    敏感词过滤在网站开发必不可少.一般用DFA,这种比较好的算法实现的. 参考链接:http://cmsblogs.com/?p=1031 一个比较好的代码实现: import java.io.IOExc ...

随机推荐

  1. Postgresql Jsonb字段内含数组属性的删除元素操作

    1.创建示例表 create temp table settings as select '{"west": [ {}, {} ]}'::jsonb as value; 2.如下保 ...

  2. jQuery MiniUI开发系列之:使用API文档

    jQuery MiniUI在组件设计上,是简约.独立的,没有复杂的继承体系. 比如使用DataGrid,可以在api文档的datagrid部分,查找到datagrid的所有属性.方法.事件,而无需关注 ...

  3. [转]云计算研究必备——精典Google论文

    Google云计算技术奠定其在业界的领先地位,收集经典云计算技术公开文章供大家研究学习: 01)GFS-The Google File System 02) Bigtable - A Distribu ...

  4. 【HOW】在InfoPath中如何为浏览和编辑模式设置不同的视图

    1. 在SharePoint Designer中打开要自定义视图的列表.并点击菜单:列表设置 > 在 InfoPath 中设计表单 > {要自定义表单的内容类型},则会自动打开InfoPa ...

  5. OPNET下 op_pk_copy()的时间问题

    op_pk_copy()是生成新的数据包,包的op_pk_create_time_get()是新数据包的生成时间,统计数据包的端到端时延,以及服务时延需要注意:

  6. Partitioning & Archiving tables in SQL Server (Part 2: Split, Merge and Switch partitions)

    Reference: http://blogs.msdn.com/b/felixmar/archive/2011/08/29/partitioning-amp-archiving-tables-in- ...

  7. 通过Windows组策略限制证书组织流氓软件的安装运行

    https://liwei2.com/2015/11/27/378.html关于如何提取证书,请参阅:https://www.zhihu.com/question/26917038http://www ...

  8. 使用localResizeIMG微信压缩上传图片安卓报错 weixin://preInjectJSBridge/fail

    微信上传图片是经常使用的功能,首先说一下使用的是:localResizeIMG进行图片压缩上传.感觉还是很好用,基本上功能都能满足. 但是最近在开发这个功能时遇到一个奇怪的问题,就是iphone|ip ...

  9. Cordova 打包 Android release app 过程详解

    Cordova 打包 Android release app 过程详解 时间 -- :: SegmentFault 原文 https://segmentfault.com/a/119000000517 ...

  10. 分拆素数和 HDU - 2098

    把一个偶数拆成两个不同素数的和,有几种拆法呢? Input输入包含一些正的偶数,其值不会超过10000,个数不会超过500,若遇0,则结束.Output对应每个偶数,输出其拆成不同素数的个数,每个结果 ...