Unicode preg_将关键字变量与本地UTF-8编码文件中的拉丁和非拉丁字符关键字列表进行匹配

Unicode preg_将关键字变量与本地UTF-8编码文件中的拉丁和非拉丁字符关键字列表进行匹配,unicode,filter,matching,multibyte,non-latin,Unicode,Filter,Matching,Multibyte,Non Latin,我有一个坏词过滤器,它使用保存在本地UTF-8编码文件中的关键字列表。该文件包括拉丁和非拉丁字符(主要是英语和阿拉伯语)。对于拉丁关键字,一切都按预期进行,但当变量包含非拉丁字符时,匹配似乎无法识别这些现有关键字 $badwords = file_get_contents("badwords.txt"); $badtemp = explode("\n", $badwords); $badwords = array_unique($badtemp); $hasBadword = 0; $que

我有一个坏词过滤器,它使用保存在本地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.txt文件每行包含一个单词

用于匹配的代码:


我读过iconv、多字节函数(mbstring)和使用运算符/u可能会有帮助,我尝试了一些方法,但似乎没有成功。如果您能帮助解决这个问题,并让它同时匹配拉丁语和非拉丁语关键字,我们将不胜感激。

PHP中的一些字符串函数不能用于UTF-8字符串,它们应该会在版本6中修复它,但现在您需要小心处理字符串

看起来
strtolower()
就是其中之一,您需要使用
mb\u strtolower($query,'UTF-8')
。如果这不能解决问题,您需要通读代码,找到处理
$query
badwords.txt
的每个点,并检查文档中是否存在UTF-8错误

据我所知,
preg_match()
可以使用UTF-8字符串,但默认情况下会禁用一些功能以提高性能。我想你不需要它们

请再次检查
badwords.txt
是否为UTF-8文件,以及
$query
是否包含有效的UTF-8字符串(如果它来自浏览器,则使用
标记进行设置)

如果您试图调试UTF-8文本,请记住,大多数web浏览器都不会默认使用UTF-8文本编码,因此,除非您选择UTF-8(在我的浏览器中,使用
查看->编码->Unicode
),否则您为调试而打印的任何PHP变量都不会被浏览器正确显示


您不需要使用
iconv
或任何其他转换API,它们中的大多数将简单地用拉丁字符替换所有非拉丁字符。显然不是你想要的。

这个问题似乎与识别单词边界有关;\b构造显然不是“Unicode感知的”。这就是问题的答案所暗示的。当使用\b时,即使文本中包含像“é”这样的拉丁字母,我也能重现这个问题。当我设置时,问题似乎消失了(也就是说,阿拉伯语单词被正确识别)

$regexp = "/" . $wstart . $val . $wend . "/iu";
并修改regexp,如下所示:


谢谢阿比的回复。文件确实是使用UTF-8保存的,查询来自使用meta charset=UTF-8的UTF-8编码页面”。我以前使用过mb_strtolower()和mb_ereg_match()它仍然匹配英语关键字,但不匹配阿拉伯语。这与浏览器默认语言无关,只是为了匹配badwords.txt文件中存在的查询关键字,然后进行进一步处理,所有演示页面都是UTF-8编码的页面。如果有任何进一步的想法,我们将不胜感激。谢谢你,这正是我们想要的我需要,它终于起作用了。我不会想到问题会是它原来的样子。在我测试各种建议时,边界regexp实际上一直保持不变。非常感谢。
$wstart = '(^|[^\p{L}])';
$wend = '([^\p{L}]|$)';
$regexp = "/" . $wstart . $val . $wend . "/iu";