
关键词过滤扩展,用于检查一段文本中是否出现敏感词,基于
Double-Array Trie树实现。
因为本项目依赖于 libdatrie, 所以需要先安装 libdatrie, 再安装本扩展。
$ wget https://github.com/tlwg/libdatrie/releases/download/v0.2.11/libdatrie-0.2.11.tar.xz $ tar zxvf libdatrie-0.2.11.tar.xz $ cd libdatrie-0.2.11 $ ./configure && make && make install PS: libdatrie 依赖于 libiconv, 如果编译的时候报 undefined reference to libiconv, 你需要先安装 libiconv。如果安装完还有错误可以执行这个命令 ./configure LDFLAGS=-L/usr/local/lib LIBS=-liconv。
$ git clone https://github.com/cdoco/xfilter.git && cd xfilter $ phpize && ./configure && make && make install 你可以在 php.ini 中设置字典文件的路径, 如果你不想在 php.ini 中设置你也可以在 setFileName 方法中设置。
[xfilter] extension=xfilter.so // 你可以在这里设置加载的字典文件路径 xfilter.filename=/path/to/xfilter/blackword.dic <?php use Cdoco\Filter; // 这个方法里可以传入词典的路径或者在 php.ini 中设置 Filter::setFileName(__DIR__ . '/blackword.dic'); // 保存敏感词到字典文件中 Filter::save(['敏感词', '高子航', 'xfilter']); // 搜索字符串中的敏感词 会返回敏感词的起始位置和长度 $rs = Filter::search('这是一个敏感词测试语句, 由高子航创造, xfilter, By ZiHang Gao。'); // Array // ( // [0] => Array // ( // [0] => 12 // [1] => 9 // ) // // [1] => Array // ( // [0] => 38 // [1] => 9 // ) // // [2] => Array // ( // [0] => 55 // [1] => 7 // ) // // ) print_r($rs); 该方法可以传入一个敏感词的字典文件路径。
Filter::setFileName(string $filename); // 示例 Filter::setFileName(__DIR__ . '/blackword.dic'); 保存一个敏感词数组到字典文件中, 如果在 setFileName 方法中设置了路径, 会优先使用 setFileName 方法中的路径, 如果没有会使用 php.ini 中设置的 xfilter.filename。
boolean Filter::save(array $blackword [, boolean $append = false]); // 示例 Filter::save(['敏感词', '高子航', 'xfilter'], true); save 方法有两个参数, 第一个参数 $blackword 是一个敏感词的数组, 第二个参数 $append 用来表示是否是追加写入。
<?php use Cdoco\Filter; Filter::setFileName(__DIR__ . '/blackword.dic'); Filter::save(['xfilter']); $rs = Filter::search('xfilter, By ZiHang Gao。'); // Array // ( // [0] => Array // ( // [0] => 0 // [1] => 7 // ) // // ) print_r($rs); // 不设置 $append 参数 save 方法会重新建立一个文件 Filter::save(['cdoco']); $rs = Filter::search('xfilter, By ZiHang Gao。'); // Array // ( // ) print_r($rs); // 如果设置了 $append 为 true, save 方法会在之前字典的基础上追加敏感词 Filter::save(['xfilter'], true); $rs = Filter::search('cdoco, By ZiHang Gao。'); // Array // ( // [0] => Array // ( // [0] => 0 // [1] => 5 // ) // // ) print_r($rs); 搜索一个字符串中是否包含敏感词。
array Filter::search(string $text); // 示例 Filter::search('这是一个敏感词测试语句, 由高子航创造, xfilter, By ZiHang Gao。'); search 方法会返回一个二维数组, 包含敏感词出现的位置和长度, 你可以用 substr 方法截取出敏感词。
Array ( [0] => Array ( [0] => 0 //敏感词出现的位置 [1] => 5 //敏感词的长度 ) ) <?php use Cdoco\Filter; // 截取字符串 $cOntent= '这是一个敏感词测试语句, 由高子航创造, xfilter, By ZiHang Gao。'; $rs = Filter::search($content); foreach ($rs as $v) { echo substr($content, $v[0], $v[1]) . "\n"; } // 敏感词 // 高子航 // xfilter 删除字典文件中的敏感词。
boolean Filter::delete(string $keyword); // 示例 Filter::delete('高子航'); @wulijun 的 trie-filter 扩展已不维护更新, 目前使用起来有点繁琐。这个项目是根据自己的想法, 在 trie-filter 的基础上修改而来, 感谢 @wulijun。
PHP License. See the LICENSE file.
1 tanszhe 2018-06-12 09:45:49 +08:00 感觉意义不大,作为学习练习还是可以。 如果加上检查一个词语在不在字符串中就 strpos 就好了。 一个词语过滤器 应当具有词语相识度识别的功能。换句话说就是这个词语没有在你的词库中 你也应该能识别出来。在实际场景中用户如果发现一个词语被限制了他会换一个词语 相近的词语。如果只是靠枚举 肯定是不全面的 而且新词语产生的非常快。词库的维护需要耗费很多精力。所有过滤器应当有自我进化的功能。 |
2 hubqin 2018-06-12 09:48:25 +08:00 via Android 我们一般的做法是建一个敏感词表或 php 文件(return 一个数组的形式),将敏感词读取出来(数组),循环判断文本中是否含有 |
5 yankebupt 2018-06-12 11:43:31 +08:00 不知道 double array trie 哪方面性能好一点... 是大文本量好一点还是大量关键词好一点... 看了一眼数据结构介绍,发现没见过. |
6 tanszhe 2018-06-12 13:52:44 +08:00 |
7 R18 2018-06-12 13:56:59 +08:00 直接用的接口,有问题也好甩锅 |
8 changwei 2018-06-12 15:04:16 +08:00 提个小建议哈,如果是强调性能的项目,最好带上 benchmark 测试结果的! |
9 Z1076 2018-06-12 17:21:46 +08:00 我是把敏感词直接扔数据库里面, 一个 where like 完事. 决定什么是敏感词都是运营那边的大佬负责添加. |
11 nullen 2018-06-12 18:07:03 +08:00 实现的蛮好。 我们之前也是用 PHP 实现的 Trie,但是敏感词越来越多,词库越来越大,效率降低; 而且 PHP 请求是运行完一次就全部销毁,逐渐成为一个瓶颈; 后来我们把敏感词单独用 Go 实现成一个服务,感觉良好。 |
12 owenliang 2018-06-12 18:28:30 +08:00 double array trie 吧? |
15 nullen 2018-06-13 10:20:21 +08:00 |