0

由于我不能使用 preg_match(UTF8 支持在某种程度上被破坏,它在本地工作但在生产中中断)我想找到另一种将单词与黑名单匹配的方法。问题是,我只想搜索字符串以进行完全匹配,而不是字符串的第一次出现。

这就是我使用 preg_match 的方式

preg_match('/\b(badword)\b/', strtolower($string));

示例字符串:

$string = "This is a string containing badwords and one badword";

我只想匹配“badwords”(最后)而不是“badwords”。

strpos('badword', $string) matches the first one

有任何想法吗?

4

4 回答 4

1

如果你想模仿\b正则表达式的修饰符,你可以尝试这样的事情:

$offset = 0;
$word = 'badword';
$matched = array();
while(($pos = strpos($string, $word, $offset)) !== false) {
    $leftBoundary = false;
    // If is the first char, it has a boundary on the right
    if ($pos === 0) {
       $leftBoundary = true;
    // Else, if it is on the middle of the string, we must check the previous char
    } elseif ($pos > 0 && in_array($string[$pos-1], array(' ', '-',...)) {
        $leftBoundary = true;
    }

    $rightBoundary = false;
    // If is the last char, it has a boundary on the right
    if ($pos === (strlen($string) - 1)) {
       $rightBoundary = true;
    // Else, if it is on the middle of the string, we must check the next char
    } elseif ($pos < (strlen($string) - 1) && in_array($string[$pos+1], array(' ', '-',...)) {
        $rightBoundary = true;
    }

    // If it has both boundaries, we add the index to the matched ones...
    if ($leftBoundary && $rightBoundary) {
        $matched[] = $pos;
    }

    $offset = $pos + strlen($word);
}
于 2013-09-12T13:29:07.127 回答
1

假设您可以进行一些预处理,您可以使用空格替换所有标点符号并将所有内容都放在小写中,然后:

  • 在 while 循环中使用strpos类似的东西strpos(' badword ', $string)来继续遍历整个文档;
  • 在空格处拆分字符串,并将每个单词与您拥有的坏单词列表进行比较。

因此,如果您尝试第一个选项,它会像这样(未经测试的伪代码)

$documet = body of text to process . ' ' 
$document.replace('!@#$%^&*(),./...', ' ')
$document.toLowerCase()
$arr_badWords = [...]
foreach($word in badwords)
{
    $badwordIndex = strpos(' ' . $word . ' ', $document)
    while(!badWordIndex)
    {
        //
        $badwordIndex = strpos($word, $document)
    }
}

编辑:根据@jonhopkins 的建议,在末尾添加一个空格应该满足文档末尾有想要的单词并且没有标点符号的情况。

于 2013-09-12T12:55:57.120 回答
0

A simple way to use word boundaries with unicode properties:

preg_match('/(?:^|[^pL\pN_])(badword)(?:[^pL\pN_]|$)/u', $string);

In fact it's much more complicated, have a look at here.

于 2013-09-12T13:24:39.133 回答
0

您可以使用strrpos()代替strpos

strrpos — 查找字符串中最后一次出现的子字符串的位置

$string = "This is a string containing badwords and one badword";
var_dump(strrpos($string, 'badword'));

输出:

45
于 2013-09-12T12:56:08.903 回答