PHP实现非法词汇过滤算法
算法简介
将关键词构造成一颗树,每个字都是一个节点。
遍历需要过滤的语句,将语句的每个字都去树中查找,看看是否存在。
实现难点
构造一棵树简单,关键点是php
中遍历字符串需要自己正确的得到单个字符的长度。
简单遍历字符串的方法如下:
$strLen = mb_strlen($str);
for ($i = 0; $i < $strLen; $i ) {
echo mb_substr($str, $i, 1, "utf8"),PHP_EOL;
}
该方法是利用mb_*
系列函数来正确截取每个字符,处理大量字符串时速度非常慢,我猜测是:mb_substr
每截取一个字符,都要计算该字符串之前,有多少个字符。
正确的遍历字符串的方式是按utf8
的编码规律来截取字符串,具体请看下文。
算法实现
<?php
/**
* 非法关键词检查
*/
class SensitiveWords
{
protected $tree = null;
protected $callIsNumeric = true;
/**
* 非法词汇列表,一个非法词汇占用一行
*/
public function __construct($path = __DIR__ . '/sensitiveWords.txt')
{
$this->tree = new WordNode();
$file = fopen($path, "r");
while (!feof($file)) {
$words = trim(fgets($file));
if ($words == '') {
continue;
}
//存在纯数字的非法词汇
if (is_numeric($words)) {
$this->callIsNumeric = false;
}
$this->setTree($words);
}
fclose($file);
}
protected function setTree($words)
{
$array = $this->strToArr($words);
$tree = $this->tree;
$l = count($array) - 1;
foreach ($array as $k => $item) {
$tree = $tree->getChildAlways($item);
if ($l == $k) {
$tree->end = true;
}
}
}
/**
* 返回包含的非法词汇
* @param string $str
* @return array
*/
public function check($str)
{
//先压缩字符串
$str = trim(str_replace([' ', "\n", "\r"], ['', '', ''], $str));
$ret = [];
loop:
$strLen = strlen($str);
if ($strLen === 0) {
return array_unique($ret);
}
//非法词汇中没有纯数字的非法词汇,待检测字符串又是纯数字的,则跳过不再检查
if ($this->callIsNumeric && is_numeric($str)) {
return array_unique($ret);
}
//挨个字符进行判断
$tree = $this->tree;
$words = '';
for ($i = 0; $i < $strLen; $i ) {
//unicode范围 --> ord 范围
//一字节 0-127 --> 0 - 127
//二字节 128-2047 --> 194 - 223
//三字节 2048-65535 --> 224 - 239
//四字节 65536-1114111 --> 240 - 244
//@see http://shouce.jb51.net/gopl-zh/ch3/ch3-05.html
$ord = ord($str[$i]);
if ($ord <= 127) {
$word = $str[$i];
} elseif ($ord <= 223) {
$word = $str[$i] . $str[$i 1];
$i = 1;
} elseif ($ord <= 239) {
$word = $str[$i] . $str[$i 1] . $str[$i 2];
$i = 2;
} elseif ($ord <= 244) {
//四字节
$word = $str[$i] . $str[$i 1] . $str[$i 2] . $str[$i 3];
$i = 3;
} else {
//五字节php都溢出了
//Parse error: Invalid UTF-8 codepoint escape sequence: Codepoint too large
continue;
}
//判断当前字符
$tree = $tree->getChild($word);
if (is_null($tree)) {
//当前字不存在,则截取后再次循环
$str = substr($str, $i 1);
goto loop;
} else {
$words .= $word;
if ($tree->end) {
$ret[] = $words;
}
}
}
return array_unique($ret);
}
protected function strToArr($str)
{
$array = [];
$strLen = mb_strlen($str);
for ($i = 0; $i < $strLen; $i ) {
$array[] = mb_substr($str, $i, 1, "utf8");
}
return $array;
}
}
/**
* 单个字符的节点
*/
class WordNode
{
//是否为非法词汇末级节点
public $end = false;
//子节点
protected $child = [];
/**
* @param string $word
* @return WordNode
*/
public function getChildAlways($word)
{
if (!isset($this->child[$word])) {
$this->child[$word] = new self();
}
return $this->child[$word];
}
/**
* @param string $word
* @return WordNode|null
*/
public function getChild($word)
{
if ($word === '') {
return null;
}
if (isset($this->child[$word])) {
return $this->child[$word];
}
return null;
}
}
这篇好文章是转载于:学新通技术网
- 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
- 本站站名: 学新通技术网
- 本文地址: /boutique/detail/tanfeace
系列文章
更多
同类精品
更多
-
photoshop保存的图片太大微信发不了怎么办
PHP中文网 06-15 -
Android 11 保存文件到外部存储,并分享文件
Luke 10-12 -
word里面弄一个表格后上面的标题会跑到下面怎么办
PHP中文网 06-20 -
《学习通》视频自动暂停处理方法
HelloWorld317 07-05 -
微信公众号没有声音提示怎么办
PHP中文网 03-31 -
photoshop扩展功能面板显示灰色怎么办
PHP中文网 06-14 -
excel下划线不显示怎么办
PHP中文网 06-23 -
excel打印预览压线压字怎么办
PHP中文网 06-22 -
怎样阻止微信小程序自动打开
PHP中文网 06-13 -
photoshop蒙版画笔没反应怎么办
PHP中文网 06-24