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

周末空余时间撸了一个敏感词过滤功能,下边记录下实现过程。

敏感词,一方面是你懂的,另一方面是我们自己可能也要过滤一些人身攻击或者广告信息等,具体词库可以google下,有很多。

过滤敏感词,使用简单的循环str_replace是性能很低效的,还会随着词库的增加,性能指数下降,而且简单的替换,不能解决一些不是完全匹配的词。这时候就需要先构建一个字典树(trie),单纯的字典树占用空间较大,使用Double-Array Trie或者Ternary Search Tree可以在保证性能的同时节省一部分空间,但是敏感词基本不会很多,几千甚至上万个词基本没压力,所以就实现就选择先构建一个字典树,然后逐字做匹配。

代码不多,就贴到这里。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
<?php

class SensitiveWordFilter
{
    private $dict;
    private $dictPath;

    public function __construct($dictPath)
    {
        $this->dict = array();
        $this->dictPath = $dictPath;
        $this->initDict();
    }

    private function initDict()
    {
        $handle = fopen($this->dictPath, ‘r‘);
        if (!$handle) {
            throw new RuntimeException(‘open dictionary file error.‘);
        }

        while (!feof($handle)) {
            $word = trim(fgets($handle, 128));

            if (empty($word)) {
                continue;
            }

            $uWord = $this->unicodeSplit($word);

            $pdict = &$this->dict;

            $count = count($uWord);
            for ($i = 0; $i < $count; $i++) {
                if (!isset($pdict[$uWord[$i]])) {
                    $pdict[$uWord[$i]] = array();
                }
                $pdict = &$pdict[$uWord[$i]];
            }

            $pdict[‘end‘] = true;
        }

        fclose($handle);
    }

    public function filter($str, $maxDistance = 5)
    {
        if ($maxDistance < 1) {
            $maxDistance = 1;
        }

        $uStr = $this->unicodeSplit($str);

        $count = count($uStr);

        for ($i = 0; $i < $count; $i++) {
            if (isset($this->dict[$uStr[$i]])) {
                $pdict = &$this->dict[$uStr[$i]];

                $matchIndexes = array();

                for ($j = $i + 1, $d = 0; $d < $maxDistance && $j < $count; $j++, $d++) {
                    if (isset($pdict[$uStr[$j]])) {
                        $matchIndexes[] = $j;
                        $pdict = &$pdict[$uStr[$j]];
                        $d = -1;
                    }
                }

                if (isset($pdict[‘end‘])) {
                    $uStr[$i] = ‘*‘;
                    foreach ($matchIndexes as $k) {
                        if ($k - $i == 1) {
                            $i = $k;
                        }
                        $uStr[$k] = ‘*‘;
                    }
                }
            }
        }

        return implode($uStr);
    }

    public function unicodeSplit($str)
    {
        $str = strtolower($str);
        $ret = array();
        $len = strlen($str);
        for ($i = 0; $i < $len; $i++) {
            $c = ord($str[$i]);

            if ($c & 0x80) {
if (($c & 0xf8) == 0xf0 && $len - $i >= 4) {
if ((ord($str[$i + 1]) & 0xc0) == 0x80 && (ord($str[$i + 2]) & 0xc0) == 0x80 && (ord($str[$i + 3]) & 0xc0) == 0x80) {
$uc = substr($str, $i, 4);
$ret[] = $uc;
$i += 3;
}
} else if (($c & 0xf0) == 0xe0 && $len - $i >= 3) {
if ((ord($str[$i + 1]) & 0xc0) == 0x80 && (ord($str[$i + 2]) & 0xc0) == 0x80) {
$uc = substr($str, $i, 3);
$ret[] = $uc;
$i += 2;
}
} else if (($c & 0xe0) == 0xc0 && $len - $i >= 2) {
if ((ord($str[$i + 1])  & 0xc0) == 0x80) {
$uc = substr($str, $i, 2);
$ret[] = $uc;
$i += 1;
}
}
} else {
$ret[] = $str[$i];
}
}
return $ret;
}
}

使用方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
require ‘SensitiveWordFilter.php‘;

/*
初始化传入词库文件路径,词库文件每个词一个换行符。
如:
敏感1
敏感2

目前只支持UTF-8编码
*/
$filter = new SensitiveWordFilter(__DIR__ . ‘/sensitive_words.txt‘);

/*
第一个参数传入要过滤的字符串,第二个是匹配的字间距,
比如‘枪支‘是一个敏感词,想过滤‘枪||||支‘的时候,
就需要指定一个两个字的间距,可以根据情况设定,
超过指定间距就不会过滤。所有匹配的敏感词会被替换为‘*‘。
*/
$filter->filter(‘这是一个敏感词‘, 10);

性能没有具体详细的做测试,不过一般场景足够,主要是吃CPU,词库可以把生成好的字典JSON编码后存到Redis或者Memcached中,下次使用直接取出还原。

PHP写WEB的话,不是Daemon这种,所以构建的数据结构不能方便的驻留内存,相比来说,C、C++、Java等可能更合适,如果对性能要求苛刻,可以用其他语言写个服务。当然,如果非要使用PHP,也可以使用Swoole封装服务。

时间: 2024-10-05 15:57:53

用php实现一个敏感词过滤功能的相关文章

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

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

转:Java实现敏感词过滤

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

Java实现敏感词过滤

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

Java实现敏感词过滤(转)

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

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

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

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

转自:http://www.infoq.com/cn/articles/alibaba-broadcast-platform-technology-challenges 鏖战双十一-阿里直播平台面临的技术挑战 作者 陈康贤 发布于 2016年1月28日 | 2 讨论 分享到:微博微信FacebookTwitter有道云笔记邮件分享 稍后阅读 我的阅读清单 前言:一直以来双十一都是以交易为重心,今年当然也是如此,但是这并不妨碍万能的淘宝将双十一打造的让用户更欢乐.体验更丰富.玩法更多样.内容更有趣

好记性不如烂笔头31-java应用中的敏感词过滤实现(3)

敏感词过滤,国内混的同学看到这个都会会心一笑.其实敏感词过滤,在几乎所有国家都是存在的,只是表现的形式并不完全相同而已. 既然这个功能叫做关键词过滤,那么做在过滤器中,应该是一个好主意. 1.JAVA实现利用过滤器实现敏感信息过滤 过滤器的JAVA代码: package com.filter; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.

java web过滤器实际应用(解决中文乱码 html标签转义功能 敏感字符过滤功能)

转载地址:http://www.cnblogs.com/xdp-gacl/p/3952405.html 在filter中可以得到代表用户请求和响应的request.response对象,因此在编程中可以使用Decorator(装饰器)模式对request.response对象进行包装,再把包装对象传给目标资源,从而实现一些特殊需求. 一.Decorator设计模式 1.1.Decorator设计模式介绍 当某个对象的方法不适应业务需求时,通常有2种方式可以对方法进行增强: 编写子类,覆盖需增强的

敏感词过滤

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