【问题标题】:Replace whole words from blacklist array instead of partial matches替换黑名单数组中的整个单词而不是部分匹配
【发布时间】:2019-09-16 21:11:18
【问题描述】:

我有一个单词数组

$banned_names = array('about','access','account');

实际数组很长 a 包含坏词,因此有可能违反任何规则我刚刚添加了一个示例,我遇到的问题如下:

$title = str_ireplace($filterWords, '****', $dn1['title']);

但是,这可行,我过滤的单词之一是“朗姆酒”,如果我要发布“论坛”这个词,它将显示为“fo****”

所以我只需要用 **** 替换这个词,如果它与数组中的确切词匹配,如果我要举一个例子,短语“让我们检查论坛,看看是否有人有朗姆酒”,将是“让我们去论坛看看有没有人有“****”。

【问题讨论】:

    标签: php arrays regex filter word


    【解决方案1】:

    您可以使用带有\W 的正则表达式来匹配“非单词”字符:

    var_dump(preg_match('/\Wrum\W/i', 'the forum thing')); // returns 0 i.e. doesn't match
    var_dump(preg_match('/\Wrum\W/i', 'the rum thing'));   // returns 1 i.e. matches
    

    preg_replace() 方法采用类似str_replace() 的过滤器数组,但您必须调整列表以包括模式分隔符和两侧的\W。您可以将完整模式静态存储在列表中:

    $banlist = ['/\Wabout\W/i','/\Waccess\W/i', ... ];
    preg_replace($banlist, '****', $text);
    

    或动态调整数组以添加这些位。

    【讨论】:

    • 使用单词边界 (\b) 而不是像 cOle2 的回答中所展示的那样包裹在 \W 中会更合适,因为它不适应列入黑名单的单词位于开头或结尾的实例字符串。
    【解决方案2】:

    与其他答案类似,但这在正则表达式中使用 \b 来匹配单词边界(整个单词)。它还会在传递给preg_replace_callback() 之前即时创建与正则表达式兼容的禁止列表。

    $dn1['title'] = 'access forum'; 
    
    $banned_names = array('about','access','account','rum');
    $banned_list = array_map(function($r) { return '/\b' . preg_quote($r, '/') . '\b/'; }, $banned_names); 
    
    $title = preg_replace_callback($banned_list, function($m) { 
       return $m[0][0].str_repeat('*', strlen($m[0])-1);
    }, $dn1['title']);
    
    echo $title; //a***** forum
    

    【讨论】:

    • 谢谢,我喜欢你的代码,但是我的一些被禁止的名字包含我认为破坏代码的特殊字符,有没有办法修改它以防止符号(包括空格、句点、下划线和破折号) 从打破它?
    • 其实认为是我自己的错误,我的一个词包含一个正斜杠,它破坏了代码。谢谢
    • @Mystic 如果您的单词有特殊字符,您可以将preg_quote() 添加到array_map 行:return '/\b' . preg_quote($r, '/') . '\b/';。我已经编辑了答案以反映这一点。
    • 这非常有用,谢谢你的编辑,因为你肯定知道你在这里的东西,我不认为你可以节省我尝试如何保留禁用词的第一个字母的时间,所以使用与你制作 $title 相同的例子会导致一个 ***** 论坛。
    • @Mystic 当然可以,只需将return str_repeat('*', strlen($m[0])); 行更改为return $m[0][0].str_repeat('*', strlen($m[0])-1);。我用更改更新了答案。
    【解决方案3】:

    在将 haystack 中的每个字符串转换为字符串数组后,您可以使用 preg_replace() 查找带有字符串开头/结尾标签的针,这样您就可以匹配完整的单词。或者,您可以添加空格并继续使用 str_ireplace() 但如果您的单词是正在检查的字符串中的第一个或最后一个单词,该选项将失败。

    添加空格(会漏掉第一个/最后一个单词,不推荐):

    当然,您必须首先修改您的过滤数组。是的,foreach 可以更简单,但我希望这能说明我在做什么/为什么。

    foreach($filterWords as $key => $value){
        $filterWords[$key] = " ".$value." ";
    }
    str_ireplace ( $filterWords, "****", $dn1['title'] );
    

    或 拆分长字符串(推荐):

    foreach($filterWords as $key => $value){
        $filterWords[$key] = "/^".$value."$/i"; //add regex for beginning/end of string value
    }
    preg_replace ( $filterWords, "****", explode(" ", $dn1['title']) );
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-02-07
      • 1970-01-01
      • 2018-05-07
      • 1970-01-01
      相关资源
      最近更新 更多