如何检查字符串是否包含特定单词?

考虑:

$a = 'How are you?';

if ($a contains 'are')
    echo 'true';

假设我有上面的代码, if ($a contains 'are') ,写语句的正确方法if ($a contains 'are')什么?

答案

您可以使用strpos()函数来查找另一个字符串中另一个字符串的出现:

$a = 'How are you?';

if (strpos($a, 'are') !== false) {
    echo 'true';
}

注意, !== false的使用是有意的( != false=== true都不会返回期望的结果)。 strpos()返回大海捞针字符串中针串开始的偏移量,或者如果找不到针,则返回布尔值false 。由于 0 是一个有效的偏移量,而 0 是 “falsey”,我们不能使用更简单的结构,例如!strpos($a, 'are')

您可以使用正则表达式,与其他用户提到的strpos相比,它在单词匹配方面更好,而且对于诸如票价,护理,凝视等字符串也将返回 true。这可以通过使用单词边界在正则表达式中简单地避免。

一个简单的匹配 are 可能看起来像这样:

$a = 'How are you?';

if (preg_match('/\bare\b/', $a)) {
    echo 'true';
}

在性能方面, strpos大约快三倍,并且要记住,当我一次进行一百万次比较时, preg_match 1.5 秒完成,而strpos用了 0.5 秒。

编辑:为了搜索字符串的任何部分,而不仅仅是逐个单词,我建议使用正则表达式,例如

$a = 'How are you?';
$search = 'are y';
if(preg_match("/{$search}/i", $a)) {
    echo 'true';
}

正则表达式末尾的i将正则表达式更改为不区分大小写,如果不希望这样,可以将其省略。

现在,在某些情况下这可能会很成问题,因为 $ search 字符串没有以任何方式进行消毒,我的意思是,在某些情况下,它可能无法通过检查,就像$search是用户输入一样,他们可以添加一些可能表现得像一些不同的正则表达式...

另外,这是一个测试和查看各种正则表达式Regex101的好工具

要将这两组功能组合为一个多功能(包括具有区分大小写的功能),可以使用以下代码:

function FindString($needle,$haystack,$i,$word)
{   // $i should be "" or "i" for case insensitive
    if (strtoupper($word)=="W")
    {   // if $word is "W" then word search instead of string in string search.
        if (preg_match("/\b{$needle}\b/{$i}", $haystack)) 
        {
            return true;
        }
    }
    else
    {
        if(preg_match("/{$needle}/{$i}", $haystack)) 
        {
            return true;
        }
    }
    return false;
    // Put quotes around true and false above to return them as strings instead of as bools/ints.
}

这是一个小的实用程序功能,在这种情况下很有用

// returns true if $needle is a substring of $haystack
function contains($needle, $haystack)
{
    return strpos($haystack, $needle) !== false;
}

尽管大多数答案都会告诉您字符串中是否出现了子字符串,但是如果您正在寻找一个特定的单词 ,那通常不是您想要的,而不是substring

有什么不同?子字符串可以出现在其他单词内:

  • “区域” 开头的 “区域”
  • “野兔” 末尾的 “是”
  • “票价” 中间的 “是”

减轻这种情况的一种方法是使用带有单词边界\b )的正则表达式:

function containsWord($str, $word)
{
    return !!preg_match('#\\b' . preg_quote($word, '#') . '\\b#i', $str);
}

该方法没有上面提到的相同的误报,但确实有一些边缘情况。单词边界与非单词字符( \W )匹配,这些字符将不是azAZ0-9_任何字符。这意味着数字和下划线将被视为单词字符,并且这样的情况将失败:

  • “您在想什么” 中的 “是”。
  • “大声笑,那些是 4” 中的 “是” 吗?

如果您想获得比这更准确的信息,则必须开始进行英语语法解析,这是一大堆蠕虫(并且无论如何都假定正确使用了语法,但并非总是这样)。

要确定一个字符串是否包含另一个字符串,可以使用 PHP 函数strpos()

int strpos ( string $haystack , mixed $needle [, int $offset = 0 ] )

<?php

$haystack = 'how are you';
$needle = 'are';

if (strpos($haystack,$needle) !== false) {
    echo "$haystack contains $needle";
}

?>

警告:

如果您要搜索的针头位于干草堆的开头,它将返回位置 0,如果执行==比较不起作用,则需要执行===

==符号是一个比较,用于测试左侧的变量 / 表达式 / 常量是否与右侧的变量 / 表达式 / 常量具有相同的值。

===符号是一个比较,以查看两个变量 / 表达式 / 常量是否相等AND具有相同的类型 - 即,两个都是字符串还是两个都是整数。

看一下strpos()

<?php
    $mystring = 'abc';
    $findme   = 'a';
    $pos = strpos($mystring, $findme);

    // Note our use of ===. Simply, == would not work as expected
    // because the position of 'a' was the 0th (first) character.
    if ($pos === false) {
        echo "The string '$findme' was not found in the string '$mystring'.";
    }
    else {
        echo "The string '$findme' was found in the string '$mystring',";
        echo " and exists at position $pos.";
    }
?>

如果您的搜索不区分大小写,则使用strstr()stristr()是另一种选择。

与 SamGoody 和 Lego Stormtroopr 同行。

如果您正在寻找一种 PHP 算法来根据多个单词的接近度 / 相关性搜索结果进行排名 ,那么这里提供了一种仅使用 PHP 即可生成搜索结果的快捷方法:

其他布尔搜索方法(例如strpos()preg_match()strstr()stristr()

  1. 无法搜索多个单词
  2. 结果排名

基于矢量空间模型tf-idf(项频率 - 文档反向频率)的 PHP 方法

听起来很困难,但非常容易。

如果要在一个字符串中搜索多个单词,核心问题是如何为每个单词分配权重?

如果我们可以根据术语在整个字符串中的代表性来对字符串中的术语进行加权,则可以按照与查询最匹配的结果对结果进行排序。

这是向量空间模型的思想,与SQL 全文搜索的工作原理相距不远:

function get_corpus_index($corpus = array(), $separator=' ') {

    $dictionary = array();

    $doc_count = array();

    foreach($corpus as $doc_id => $doc) {

        $terms = explode($separator, $doc);

        $doc_count[$doc_id] = count($terms);

        // tf–idf, short for term frequency–inverse document frequency, 
        // according to wikipedia is a numerical statistic that is intended to reflect 
        // how important a word is to a document in a corpus

        foreach($terms as $term) {

            if(!isset($dictionary[$term])) {

                $dictionary[$term] = array('document_frequency' => 0, 'postings' => array());
            }
            if(!isset($dictionary[$term]['postings'][$doc_id])) {

                $dictionary[$term]['document_frequency']++;

                $dictionary[$term]['postings'][$doc_id] = array('term_frequency' => 0);
            }

            $dictionary[$term]['postings'][$doc_id]['term_frequency']++;
        }

        //from http://phpir.com/simple-search-the-vector-space-model/

    }

    return array('doc_count' => $doc_count, 'dictionary' => $dictionary);
}

function get_similar_documents($query='', $corpus=array(), $separator=' '){

    $similar_documents=array();

    if($query!=''&&!empty($corpus)){

        $words=explode($separator,$query);

        $corpus=get_corpus_index($corpus, $separator);

        $doc_count=count($corpus['doc_count']);

        foreach($words as $word) {

            if(isset($corpus['dictionary'][$word])){

                $entry = $corpus['dictionary'][$word];


                foreach($entry['postings'] as $doc_id => $posting) {

                    //get term frequency–inverse document frequency
                    $score=$posting['term_frequency'] * log($doc_count + 1 / $entry['document_frequency'] + 1, 2);

                    if(isset($similar_documents[$doc_id])){

                        $similar_documents[$doc_id]+=$score;

                    }
                    else{

                        $similar_documents[$doc_id]=$score;

                    }
                }
            }
        }

        // length normalise
        foreach($similar_documents as $doc_id => $score) {

            $similar_documents[$doc_id] = $score/$corpus['doc_count'][$doc_id];

        }

        // sort from  high to low

        arsort($similar_documents);

    }   

    return $similar_documents;
}

情况 1

$query = 'are';

$corpus = array(
    1 => 'How are you?',
);

$match_results=get_similar_documents($query,$corpus);
echo '<pre>';
    print_r($match_results);
echo '</pre>';

结果

Array
(
    [1] => 0.52832083357372
)

案例 2

$query = 'are';

$corpus = array(
    1 => 'how are you today?',
    2 => 'how do you do',
    3 => 'here you are! how are you? Are we done yet?'
);

$match_results=get_similar_documents($query,$corpus);
echo '<pre>';
    print_r($match_results);
echo '</pre>';

结果

Array
(
    [1] => 0.54248125036058
    [3] => 0.21699250014423
)

情况 3

$query = 'we are done';

$corpus = array(
    1 => 'how are you today?',
    2 => 'how do you do',
    3 => 'here you are! how are you? Are we done yet?'
);

$match_results=get_similar_documents($query,$corpus);
echo '<pre>';
    print_r($match_results);
echo '</pre>';

结果

Array
(
    [3] => 0.6813781191217
    [1] => 0.54248125036058
)

尚有很多改进,但是该模型提供了一种从自然查询中获得良好结果的方法,这些自然查询没有布尔运算符,例如strpos()preg_match()strstr()stristr()

诺塔 · 贝内

(可选)在搜索单词之前消除冗余

  • 从而减小索引大小并减少存储需求

  • 更少的磁盘 I / O

  • 索引编制速度更快,因此搜索速度更快。

1. 归一化

  • 将所有文本转换为小写

2. 消除停用词

  • 从文本中消除没有实际含义的单词(例如 “和”,“或”,“该”,“用于” 等)

3. 字典替换

  • 用具有相同或相似含义的其他单词替换单词。 (例如:用 “饥饿” 替换 “饥饿” 和 “饥饿” 的实例)

  • 可以执行其他算法措施(雪球)以进一步将单词还原为其基本含义。

  • 用十六进制等效项替换颜色名称

  • 通过降低精度来减少数值是规范文本的其他方法。

资源

通过stripos()使用不区分大小写的匹配

if (stripos($string,$stringToSearch) !== false) {
    echo 'true';
}

如果要避免出现 “假” 和 “真实” 问题,可以使用 substr_count:

if (substr_count($a, 'are') > 0) {
    echo "at least one 'are' is present!";
}

它比 strpos 慢一点,但是避免了比较问题。