用php实现一个敏感词过滤功能
2016-07-20 16:57
253 查看
周末空余时间撸了一个敏感词过滤功能,下边记录下实现过程。
敏感词,一方面是你懂的,另一方面是我们自己可能也要过滤一些人身攻击或者广告信息等,具体词库可以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); |
PHP写WEB的话,不是Daemon这种,所以构建的数据结构不能方便的驻留内存,相比来说,C、C++、Java等可能更合适,如果对性能要求苛刻,可以用其他语言写个服务。当然,如果非要使用PHP,也可以使用Swoole封装服务。
相关文章推荐
- PHP-无限级分类
- PHP转换文本框内容为HTML格式的方法
- PHP 如何查看数据库中数据表是否存在
- PHP中cookie、localStorage、session、的用法
- php如何一起查询多个数据库的所有表?
- PHP购物车类Cart.class.php定义与用法示例
- php用chuanzhi的mvc模式增删改查分析
- 如何在虚拟机搭建ftp服务器供宿主机下载文件
- 从0开始一步一步用Laravel5.2集成原生微信支付
- PHP之:随机抽取一个数&&随机函数
- thinkphp中分页类改写,实现类似ajax效果;
- ThinkPHP - 常用的配置项
- ThinkPHP - 加载第三方类库
- WindowManager.LayoutParams.type属性
- thinkPHP2.1自定义标签库的导入方法详解
- php取得当前时间函数
- FTP命令详解
- php自定义函数实现二维数组排序功能
- 发送邮件(php操作email)
- 使用php向mysql中插入当前时间