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

敏感词,一方面是你懂的,另一方面是我们自己可能也要过滤一些人身攻击或者广告信息等,具体词库可以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. java程序打包成jar

    1. 建立文件夹:proj,在该文件夹下建立3个子文件夹:lib,src 2. 在lib文件夹中放置依赖的jar包 3. 在src中放置类文件:com.cnjava.demo.Main.java 4. ...

  2. poj1182食物链_并查集_挑战程序设计竞赛例题

    食物链 Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 65534   Accepted: 19321 Description ...

  3. 【目录】Leetcode

    Leetcode 1.动态规划 Palindrome Partitioning II(hard) ☆ Distinct Subsequences(hard) Edit Distance (hard) ...

  4. C/C++中无条件花括号的妙用

    C/C++中无条件花括号可以形成一个代码块,一个作用域.可以使括号内定义的变量就只在本域(就是这个大括号)内有效,而且不会影响其他域,即使名字相同. 在花括号内,如果变量前面带类型,则相当于新创建一个 ...

  5. MongoDB 安装

    年初换了个硬盘空间更大的vps,这下终于可以装MongoDB了. 1 配置包管理系统(yum) 建立 /etc/yum.repos.d/mongodb-org-3.2.repo文件.内容如下: [mo ...

  6. HDU 5769 Substring 后缀数组

    Substring Problem Description ?? is practicing his program skill, and now he is given a string, he h ...

  7. StringEscapeUtils类的转义与反转义方法

    第一步.下载Jar包(commons-lang.jar) 下载地址:http://commons.apache.org/proper/commons-lang/download_lang.cgi 第二 ...

  8. 疑问:line-height对非文字行内块的影响

    line-height:对子元素是非文字的行内块,表现出来的不是垂直居中.目前还不知道具体细节. 可以看出来两个东西不在一行.老师的解释是line-height对非文字元素解释不一样,但是我没懂细节. ...

  9. Shell 编程基础之 && 与 ||

    一.引言 Shell 在执行某个命令的时候,会返回一个返回值,该返回值保存在 shell 变量 $? 中.当 $? == 0 时,表示执行成功:当 $? == 1 时,表示执行失败.有时候,下一条命令 ...

  10. 黑科技装点圣诞节,美国邮政局用AR APP邮寄圣诞包裹

    AR手游<精灵宝可梦Go>的出现将增强现实技术带到了众人的视线中,各大公司纷纷紧抓AR的发展前景,同时积极将AR功能引入自家产品中.临近圣诞,又到了一年一度的快递高峰期,据591ARVR资 ...