原文地址:http://blog.11034.org/2012-07/trie_in_php.html

项目需求,要做敏感词过滤,对于敏感词本身就是一个CRUD的模块很简单,比较麻烦的就是对各种输入的敏感词检测了。用Trie树来实现是比较通用的一种办法吧,之前一直没机会用过这种数据结构,正好试着写了一下。

因为用PHP实现,关联数组用的很舒服。第一个要解决的是字符集的问题,如果在Java中就比较好办统一的Unicode,在PHP中因为常用 UTF-8字符集,默认有1-4个字节不同的长度来表示一个字符,于是写了个Util类来将普通的UTF-8字符串转换成字符数组,每一个元素是一个 UTF-8串形成的字符。这一点比较容易实现的,根据UTF-8字符集的格式而来就好。

public static function get_chars($utf8_str){
$s = $utf8_str;
$len = strlen($s);
if($len == 0) return array();
$chars = array();
for($i = 0;$i < $len;$i++){
$c = $s[$i];
$n = ord($c);
if(($n >> 7) == 0){ //0xxx xxxx, asci, single
$chars[] = $c;
}
else if(($n >> 4) == 15){ //1111 xxxx, first in four char
if($i < $len - 3){
$chars[] = $c.$s[$i + 1].$s[$i + 2].$s[$i + 3];
$i += 3;
}
}
else if(($n >> 5) == 7){ //111x xxxx, first in three char
if($i < $len - 2){
$chars[] = $c.$s[$i + 1].$s[$i + 2];
$i += 2;
}
}
else if(($n >> 6) == 3){ //11xx xxxx, first in two char
if($i < $len - 1){
$chars[] = $c.$s[$i + 1];
$i++;
}
}
}
return $chars;
}

字符单位确认以后,就是写Trie树了。简单的算法,从根路径开始给每个字符建一个关联数组,当字符串结束的时候,用一个null表示结尾。

删除一个串,只要找到串中任意一个字符的子元素数量为1,就表示只有这个串了,整个删除就好了;若子元素数量大于1,则继续根据字符找下去,直到末尾的null。

查找一个串(完全匹配),一直根据字符找到null为止就表明存在,任一字符不存在就表明串不存在。

验证一个长串是否含有任一串,这边算法比较挫,按照每个字符开始都在Trie树种搜索一遍,走的回头路比较多,复杂度有O(n * m),n为长串长度,m为Trie树深度,不过因为中文Trie树深度很浅,勉强还过得去(英文字符串深度很长)。

然后因为PHP没有全局缓存的机制,每次都要从数据库中读取全部的敏感词,然后建立Trie树再去匹配串的话太麻烦了,采取的办法是将Trie内部 的关联数组序列化后直接保存在数据库中,每次只要读取这条数据,然后反序列化,Trie树就回来了。当然进行串的插入和删除,将更新这个序列化数据。

可改进的地方:

当某一条路径只有这个串即关联数组数量为1时,可以压缩子树 
改进Trie树为AC自动机,即每个节点都添加一个失败指针,指向匹配失败后回到树的哪个节点,这样就仅仅是O(n)的复杂度了。建树的过程比较复杂,对每个插入的串的子串进行处理,运行时查询的效率非常高

class TrieTree{
public $tree = array();
public function insert($utf8_str){
$chars = &UTF8Util::get_chars($utf8_str);
$chars[] = null; //串结尾字符
$count = count($chars);
$T = &$this->tree;
for($i = 0;$i < $count;$i++){
$c = $chars[$i];
if(!array_key_exists($c, $T)){
$T[$c] = array(); //插入新字符,关联数组
}
$T = &$T[$c];
}
}
public function remove($utf8_str){
$chars = &UTF8Util::get_chars($utf8_str);
$chars[] = null;
if($this->_find($chars)){ //先保证此串在树中
$chars[] = null;
$count = count($chars);
$T = &$this->tree;
for($i = 0;$i < $count;$i++){
$c = $chars[$i];
if(count($T[$c]) == 1){ //表明仅有此串
unset($T[$c]);
return;
}
$T = &$T[$c];
}
}
}
private function _find(&$chars){
$count = count($chars);
$T = &$this->tree;
for($i = 0;$i < $count;$i++){
$c = $chars[$i];
if(!array_key_exists($c, $T)){
return false;
}
$T = &$T[$c];
}
return true;
}
public function find($utf8_str){
$chars = &UTF8Util::get_chars($utf8_str);
$chars[] = null;
return $this->_find($chars);
}
public function contain($utf8_str, $do_count = 0){
$chars = &UTF8Util::get_chars($utf8_str);
$chars[] = null;
$len = count($chars);
$Tree = &$this->tree;
$count = 0;
for($i = 0;$i < $len;$i++){
$c = $chars[$i];
if(array_key_exists($c, $Tree)){ //起始字符匹配
$T = &$Tree[$c];
for($j = $i + 1;$j < $len;$j++){
$c = $chars[$j];
if(array_key_exists(null, $T)){
if($do_count){
$count++;
}
else{
return true;
}
}
if(!array_key_exists($c, $T)){
break;
}
$T = &$T[$c];
}
}
}
if($do_count){
return $count;
}
else{
return false;
}
}
public function contain_all($str_array){
foreach($str_array as $str){
if($this->contain($str)){
return true;
}
}
return false;
}
public function export(){
return serialize($this->tree);
}
public function import($str){
$this->tree = unserialize($str);
}
}

转,敏感词过滤,PHP实现的Trie树的更多相关文章

  1. [转载]敏感词过滤,PHP实现的Trie树

    原文地址:http://blog.11034.org/2012-07/trie_in_php.html 项目需求,要做敏感词过滤,对于敏感词本身就是一个CRUD的模块很简单,比较麻烦的就是对各种输入的 ...

  2. [原创] Trie树 php 实现敏感词过滤

    目录 背景 简介 存储结构 PHP 其他语言 字符串分割 示例代码 php 优化 缓存字典树 常驻服务 参考文章 背景 项目中需要过滤用户发送的聊天文本, 由于敏感词有将近2W条, 如果用 str_r ...

  3. DFA和trie特里实现敏感词过滤(python和c语言)

    今天的项目是与完成python开展,需要使用做关键词检查,筛选分类,使用前c语言做这种事情.有了线索,非常高效,内存小了,检查快. 到达python在,第一个想法是pip基于外观的c语言python特 ...

  4. 用php实现一个敏感词过滤功能

    周末空余时间撸了一个敏感词过滤功能,下边记录下实现过程. 敏感词,一方面是你懂的,另一方面是我们自己可能也要过滤一些人身攻击或者广告信息等,具体词库可以google下,有很多. 过滤敏感词,使用简单的 ...

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

    为了提高查找效率,这里将敏感词用树形结构存储,每个节点有一个map成员,其映射关系为一个string对应一个TreeNode. STL::map是按照operator<比较判断元素是否相同,以及 ...

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

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

  7. PHP实现敏感词过滤系统

    PHP实现敏感词过滤系统 安装说明 安装PHP扩展 trie_filter,安装教程 http://blog.41ms.com/post/39.html 安装PHP扩展 swoole,安装教程 htt ...

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

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

  9. Java实现敏感词过滤

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

随机推荐

  1. winform窗体 控件【MDI 窗体容器】

    MDI :窗体容器 -- 在窗体中放置窗体 属性 IsMdiContainer  : 是否是窗体          -- 只有 Form 有此属性    Form2 f2 = new Form2(); ...

  2. 【Java基础】8、java中的native方法

    native是与C++联合开发的时候用的!java自己开发不用的! 使用native关键字说明这个方法是原生函数,也就是这个方法是用C/C++语言实现的,并且被编译成了DLL,由java去调用.这些函 ...

  3. 使用JDBC一次执行多条语句(以MySQL为例)

    阅读本文需要的先修知识: 最基本的SQL语句 最基本的JDBC操作(如插入单条记录) 如急需使用请直接看最后一段代码. 在JDBC中,对记录进行修改操作最简单的方法是使用executeUpdate() ...

  4. Android - 系统开机你知道多少?

    https://github.com/zhantong/interview/blob/master/Android/Android.md#38-android%E7%B3%BB%E7%BB%9F%E5 ...

  5. JSP学习笔记(6)-使用数据库

    1.连接MySQL数据库 1.1.JDBC JDBC(Java Database Connectivity)提供了访问数据库的API,由一些Java类和接口组成,是Java运行平台核心库中的一部分.用 ...

  6. HDU3625(SummerTrainingDay05-N 第一类斯特林数)

    Examining the Rooms Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Othe ...

  7. node 静态伺服(搭建服务)

    基本功能 不急着写下第一行代码,而是先梳理一下就基本功能而言有哪些步骤. 在本地根据指定端口启动一个http server,等待着来自客户端的请求 当请求抵达时,根据请求的url,以设置的静态文件目录 ...

  8. Nginx的访问认证

    1.设置访问认证的作用: 在实际的工作中,有时候我们会接到给网站加密的任务,就是需要有用户名和密码才能访问网站的内容,这个一般会是在企业的内部web服务上面来实现,其实也很简单就两个参数 语法: lo ...

  9. Mariadb MySQL、Mariadb中GROUP_CONCAT函数使用介绍

    MySQL.Mariadb中GROUP_CONCAT 函数使用介绍 By:授客 QQ:1033553122 语法: GROUP_CONCAT([DISTINCT] column_name [ORDER ...

  10. Linux 配置iso系统盘为本地yum源

    Linux配置iso系统盘为本地yum源 by:授客 QQ:1033553122   1.目的 安装软件时,经常会遇到包或类库的依赖性问题,为此,我们可以通过yum命令安装软件,尽量避免出现繁琐的软件 ...