前言
最近做一个用PHP检测字符串是否包含敏感词的功能,遇到了点问题记录一下。
一、实现方式
preg_match_all 执行一个全局正则表达式匹配,示例代码如下。
示例(1)
$word = 'fuck'; //敏感词
$content = 'fuck Tony'; //待检测内容
preg_match_all('(\b' . $word . '\b)i', $content, $matchs);
if($matchs[0]){
echo "包含敏感词:".implode(',',$matchs[0]);
die;
}
echo 'nb plus';
die;
执行结果:
包含敏感词:fuck
示例(2)
$word = 'fuck'; //敏感词
$content = 'fucker Tony'; //待检测内容
preg_match_all('(\b' . $word . '\b)i', $content, $matchs);
if($matchs[0]){
echo "包含敏感词:".implode(',',$matchs[0]);
die;
}
echo 'nb plus';
die;
执行结果:
nb plus
实践证明此方法可行,跟预期执行结果一样。
二、问题
如果待检测的字符串是中文、英文或数字等组合,上面例子可以完美实现需求。如果包含比较特殊的字符就暴露出了问题。
示例(3)
$word = 'lá'; //敏感词(越南语)
$content = 'người lái chuyên dụng tiện lợi'; //待检测内容(越南语)
preg_match_all('(\b' . $word . '\b)i', $content, $matchs);
if($matchs[0]){
echo "包含敏感词:".implode(',',$matchs[0]);
die;
}
echo 'nb plus';
die;
执行结果:
包含敏感词:lá
执行结果感到意外,lái包含lá结果被当成了敏感词了,所以上面的正则匹配是有漏洞的。
三、解决方式
这个问题有点懵,没有啥思路解决。好在功夫不负有心人,在强大的搜索引擎下找到了解决问题的蛛丝马迹。找到了一篇文章【点击跳转】。
大概意思是字符串中包含Unicode字符时,使用正则表达 /(\b##)/i 匹配单词边界不好使,必须使用\u修饰 /(\b##)/iu
eaaa… 似懂非懂。不过此方法确实解决了我的问题。调整后代码如下,正则表达式后面加了个u
示例(4)
$word = 'lá'; //敏感词(越南语)
$content = 'người lái chuyên dụng tiện lợi'; //待检测内容(越南语)
preg_match_all('(\b' . $word . '\b)iu', $content, $matchs);
if($matchs[0]){
echo "包含敏感词:".implode(',',$matchs[0]);
die;
}
echo 'nb plus';
die;
执行结果:
nb plus
总结
对正则的理解停留在搜索引擎,自己写有点困难,有待提升。对此问题的解决也是似懂非懂。
关于正则表达式\b的意思可以网上搜索,这里提供一篇文章【点击跳转】