PHP 匹配整个单词的子串

PHP substring matching whole words

我正在尝试编写一个 StringMatch 函数,当一个字符串中的单词可以在另一个字符串中找到时,该函数 return 为真。例外是我不想匹配复数和其他后缀之类的东西,我也想避免在单词有前缀时进行匹配。

更直观的解释:

apple watch - apple watches (no match)
apple watch - apple watch repairs (match)
apple watch - new apple watch (match)
apple watch - pineapple watch (no match)

我想是这样的:

echo StringMatch("apple watch", "apple watches");       // output 0
echo StringMatch("apple watch", "apple watch repairs"); // output 1
echo StringMatch("apple watch", "new apple watch");     // output 1
echo StringMatch("apple watch", "pineapple watch");     // output 0

我在 strpos() 方面取得了一些基本的成功,当第二个字符串包含上述示例中的后缀或前缀时,我无法弄清楚如何 return “0”。

这是我尝试解决的方法:

function StringMatch($str1,$str2)
{
    if (SomeFunctionOrRegex($str1,$str2) !== false)
    {
        return(1);
    }
    else
    {
        return(0);
    }
}

也许有一个优雅的正则表达式解决方案。我试过 strpos() 但它不够严格,无法满足我的需要。

就像我在评论里说的那样

function StringMatch($str1,$str2)
{
  return preg_match('/\b'.preg_quote($str1,'/').'\b/i', $str2);
}

echo StringMatch("apple watch", "apple watches");       // output 0
echo "\n";
echo StringMatch("apple watch", "apple watch repairs"); // output 1
echo "\n";
echo StringMatch("apple watch", "new apple watch");     // output 1
echo "\n";
echo StringMatch("apple watch", "pineapple watch");     // output 0
echo "\n";

输出:

0
1
1
0

Sandbox

Preg 引用是必要的,以避免 $str1 可能包含 . 之类的问题,在正则表达式中它是任何字符。

此外,您可以像这样去除标点符号

$str1 = preg_replace('/[^\w\s]+/', '', $str1);

例如:

echo StringMatch("apple watch.", "apple watch repairs"); // output 1

如果不删除标点符号,这将 return0。重要与否取决于您。

Sandbox

更新

乱序匹配,例如:

//words out of order
echo StringMatch("watch apple", "new apple watch");     // output 1

简单的方法是implode/explode:

function StringMatch($str1,$str2)
{
  //use one or the other
  $str1 = preg_replace('/[^\w\s]+/', '', $str1);
  //$str1 = preg_quote($str1,'/');
  $words = explode(' ', $str1);
  preg_match_all('/\b('.implode('|',$words).')\b/i', $str2,     $matches);
  return count($words) == count($matches[0]) ? '1' : '0';
}

Sandbox

您也可以跳过 explode/implode 并使用

 $str1 = preg_replace('/\s/', '|', $str1);

哪个可以和另一个组合preg_replace

 $str1 = preg_replace(['/[^\w\s]+/','/\s/'], ['','|'], $str1);

或者一起

function StringMatch($str1,$str2)
{
  $str1 = preg_replace(['/[^\w\s]+/','/\s/'], ['','|'], $str1);
  preg_match_all('/\b('.$str1.')\b/i', $str2, $matches);
  return (substr_count($str1, '|')+1) == count($matches[0]) ? '1' : '0';
}

Sandbox

但是当然你不能计算单词数组,但是你可以计算 | 管道的数量,它比单词的数量少 1(因此是 +1)。也就是说,如果您关心所有单词是否匹配。

  • 首先,正则表达式并不总是最好的解决方案。正则表达式需要编译。
  • 其次,您可以根据 space 拆分单词,现在您有一组单独的单词。使用 in_array() 并检查大海捞针中的每个单词。

代码:

<?php

function StringMatch($needle,$haystack){
    $domain_of_words = explode(" ",$haystack);
    $words = explode(" ",$needle);
    foreach($words as $each_word){
        if(!in_array($each_word,$domain_of_words,true)){
            return 0;
        }
    }
    return 1;
}

echo StringMatch("apple watch","apple watches repairs"),"<br/>";
echo StringMatch("apple watch","apple watch repairs");