【问题标题】:match whole word only without regex仅匹配整个单词而不使用正则表达式
【发布时间】:2013-09-16 20:57:00
【问题描述】:

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

这就是我使用 preg_match 的方式

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

示例字符串:

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

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

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

有什么想法吗?

【问题讨论】:

  • 将字符串拆分为空格,并根据您的黑名单检查每个单词
  • @jonhopkins 这不适用于标点符号(假设会有一些)。
  • 真的.. 没想到。当然有办法去掉标点符号吗?
  • 它在生产中究竟是如何中断的?哪个是你的 PHP 版本,哪个是生产服务器的 PHP 版本?
  • @HenriqueBarcelos 它只是不匹配,我最终使用 mb_ereg 而不是 preg_match - 成功了。

标签: php regex strpos


【解决方案1】:

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

  • 在 while 循环中使用 strposstrpos(' 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 的建议,在末尾添加一个空格应该满足文档末尾有想要的单词并且没有标点符号的情况。

【讨论】:

  • 如果坏词是文档中的第一个词,或者是最后一个词并且后面没有标点符号怎么办?我不认为这会匹配它。但是是否可以在 $document 的开头和结尾添加一个空格来确定?
  • @jonhopkins:我同意。根据您的建议修改了答案。
【解决方案2】:

您可以使用strrpos() 代替strpos

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

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

输出:

45

【讨论】:

  • 这假定程序员知道该字符串。如果从用户输入中检索字符串,则黑名单中的单词可能会出现在另一个匹配的单词之前,因此除了上面的测试用例之外,这不一定适用。
【解决方案3】:

使用带有 unicode 属性的单词边界的简单方法:

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

其实要复杂得多,看看here

【讨论】:

    【解决方案4】:

    如果您想模仿正则表达式的 \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);
    }
    

    【讨论】:

      猜你喜欢
      • 2017-07-08
      • 2010-11-15
      • 2012-01-06
      相关资源
      最近更新 更多