欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  后端开发

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

程序员文章站 2024-01-21 12:08:22
...
周末空余时间撸了一个敏感词过滤功能,下边记录下实现过程。

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

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

代码不多,就贴到这里。

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 unicodeSplit($str); $count = count($uStr); for ($i = 0; $i dict[$uStr[$i]])) { $pdict = &$this->dict[$uStr[$i]]; $matchIndexes = array(); for ($j = $i + 1, $d = 0; $d = 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; }}

使用方法

filter('这是一个敏感词', 10);

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

PHP写WEB的话,不是Daemon这种,所以构建的数据结构不能永久驻留内存,相比来说,C、C++、Java等可能更合适,如果对性能要求苛刻,可以用其他语言写个服务。当然,这里PHP还有个Swoole可用,但是个人不是很看好。