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

敏感词,一方面是你懂的,另一方面是我们自己可能也要过滤一些人身攻击或者广告信息等,具体词库可以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封装服务。

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

  1. Java实现敏感词过滤 - IKAnalyzer中文分词工具

    IKAnalyzer 是一个开源的,基于java语言开发的轻量级的中文分词工具包. 官网: https://code.google.com/archive/p/ik-analyzer/ 本用例借助 I ...

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

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

  3. 5分钟Serverless实践 | 构建无服务器的敏感词过滤后端系统

    前言 在上一篇“5分钟Serverless实践”系列文章中,我们介绍了什么是Serverless,以及如何构建一个无服务器的图片鉴黄Web应用,本文将延续这个话题,以敏感词过滤为例,介绍如何构建一个无 ...

  4. Java实现敏感词过滤

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

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

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

  6. Java实现敏感词过滤(转)

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

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

    转载地址:http://www.cnblogs.com/xdp-gacl/p/3952405.html 在filter中可以得到代表用户请求和响应的request.response对象,因此在编程中可 ...

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

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

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

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

随机推荐

  1. JavaScript "自"运行-setInertval()和setTimeout()理解

    setInterval()和clearInterval() var result = "Y"; function onOk() { var tid = setInterval(fu ...

  2. vmware12 ubuntu14.01桥接模式静态IP上网

    一家之言,希望能帮你解决问题.此处更多为我自留备忘. 环境: win7:机安装支持桥接模式的服务. vmware12 ubutu 14.01 注意事项(此处坑多): 1.networking rest ...

  3. python之函数

    本节主要内容: 1. 上节遗留的内置函数: callable(), chr(),ord(), compile(), eval(),exec(), divmod(), isinstance() ,fil ...

  4. SQLite -- 分页查询

    原文:http://blog.csdn.net/lu1024188315/article/details/51734514 参考:http://www.runoob.com/sqlite/sqlite ...

  5. 常见开发需求之js处理url汉字编码中的乱码

    需求及解决    两个页面传值的需求是很常见的,angular中有很多常见的方法用于传值,而且都不会受到字符编码的影响,而采用传统的url中拼字符串进行传值的操作,如果拼串中涉及到中文字符,我们就要考 ...

  6. Java数组技巧攻略

      Java数组技巧攻略 0.  声明一个数组(Declare an array) String[] aArray = new String[5]; String[] bArray = {" ...

  7. 《DSP using MATLAB》示例Example5.11

  8. BZOJ 2844 albus就是要第一个出场 ——高斯消元 线性基

    [题目分析] 高斯消元求线性基. 题目本身不难,但是两种维护线性基的方法引起了我的思考. void gauss(){ k=n; F(i,1,n){ F(j,i+1,n) if (a[j]>a[i ...

  9. zorka源码解读之Instrument实现原理

    主要用到三方面技术: beanshell来实现可扩展:告诉zorkaAgent插桩的具体需求,包括插桩的方法和值.插桩的时机.插桩追踪记录方式等. Instrument来通过代理的方式访问JVM,实现 ...

  10. 未能添加对***.dll的引用问题

    在机器A上运行.编译成功的程序,在B上不能正确被编译,并且添加r如 knbook.dll 时候提示如下: 未能添加对"knbook.dll"引用,请确保此文件可以访问并且是一个有效 ...