我有一个坏词过滤器,它使用保存在本地 UTF-8 编码文件中的关键字列表。该文件包括拉丁字符和非拉丁字符(主要是英语和阿拉伯语)。对于拉丁关键字,一切都按预期工作,但是当变量包含非拉丁字符时,匹配似乎无法识别这些现有关键字。
如何匹配拉丁语和非拉丁语关键字。
badwords.txt 文件每行包含一个单词,如本例所示
bad
nasty
racist
سفالة
وساخة
جنس
bad
nasty
racist
سفالة
وساخة
جنس
用于匹配的代码:
我读过 iconv、多字节函数(mbstring)和使用运算符 /u 可能对此有所帮助,我尝试了一些方法,但似乎没有得到正确的结果。任何帮助解决这个问题,并让它匹配拉丁和非拉丁关键字的帮助将不胜感激。
问题似乎与识别单词边界有关;该结构显然不“支持 Unicode”。这就是问题 php regex word border matches in utf-8 的答案似乎表明的内容。即使使用包含拉丁字母(如“é”)的文本,我也能够重现该问题。当我设置时,问题似乎消失了(即阿拉伯单词被正确识别)
$badwords = file_get_contents("badwords.txt");
$badtemp = explode("\n", $badwords);
$badwords = array_unique($badtemp);
$hasBadword = 0;
$query = strtolower($query);
foreach ($badwords as $key => $val) {
if (!empty($val)) {
$val = trim($val);
$regexp = "/\b" . $val . "\b/i";
if (preg_match($regexp, $query))
$badFlag = 1;
if ($badFlag == 1) {
// Bad word detected die...
}
}
}
并修改正则表达式如下:
$badwords = file_get_contents("badwords.txt");
$badtemp = explode("\n", $badwords);
$badwords = array_unique($badtemp);
$hasBadword = 0;
$query = strtolower($query);
foreach ($badwords as $key => $val) {
if (!empty($val)) {
$val = trim($val);
$regexp = "/\b" . $val . "\b/i";
if (preg_match($regexp, $query))
$badFlag = 1;
if ($badFlag == 1) {
// Bad word detected die...
}
}
}
PHP 中的某些字符串函数不能用于 UTF-8 字符串,据说他们将在版本 6 中修复它,但现在您需要小心处理字符串。
看起来
$wstart = '(^|[^\p{L}])';
$wend = '([^\p{L}]|$)';
就是其中之一,你需要使用$regexp = "/" . $wstart . $val . $wend . "/iu";
。如果这不能解决问题,您需要通读代码并找到处理 strtolower()
或 mb_strtolower($query, 'UTF-8')
的每个点,并检查 UTF-8 错误的文档。
据我所知,
$query
对于UTF-8字符串来说是可以的,但是默认情况下会禁用一些功能以提高性能。我认为您不需要其中任何一个。
另请仔细检查
badwords.txt
是否为 UTF-8 文件,并且 preg_match()
包含有效的 UTF-8 字符串(如果它来自浏览器,则使用 badwords.txt
标签进行设置)。
如果您尝试调试 UTF-8 文本,请记住大多数 Web 浏览器不会默认使用 UTF-8 文本编码,因此您打印出来用于调试的任何 PHP 变量都不会被浏览器正确显示,除非您选择 UTF -8(在我的浏览器中,带有
$query
)。
您不需要使用
<meta>
或任何其他转换 API,它们中的大多数都会简单地将所有非拉丁字符替换为拉丁字符。显然不是你想要的。