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


考虑:

$a = 'How are you?';

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

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


2668


起源




答案:


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

$a = 'How are you?';

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

注意使用 !== false 是刻意的; strpos() 返回针字符串在haystack字符串中开始的偏移量或布尔值 false 如果找不到针头。由于0是有效偏移量而0是“假”,因此我们不能使用更简单的结构 !strpos($a, 'are')


5448



我找到的一件事是,如果“是”是第一个单词,那么上面的代码将失败,因为它返回“0”,这可以被认为是假的!为了避免这种情况,它应该读取(strpos(“x”。$ a,'are')!== false)..... - Darknight
@Darknight:使用时,“0”不被视为“假”!==。只考虑使用!=。 - Milan Babuškov
聚会很晚,但要小心这一点。对于字符串'你在乎吗?',这也会返回true - DTest
@DTest - 当然它会返回true,因为字符串包含'are'。如果您正在寻找单词ARE,那么您需要进行更多检查,例如,检查A之前和之后是否有字符或空格。 - jsherk
上面的评论非常好!我从不使用!=或==,毕竟!==和===是最佳选择(在我看来)所有方面都考虑(速度,准确度等)。 - Melsi


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

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

$a = 'How are you?';

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

在性能方面,strpos的速度提高了大约三倍,并且考虑到,当我同时进行一百万次比较时,它需要1.5分钟的预匹配,并且需要花费0.5秒。


451



感谢您的建议,您的代码效果很好,但我更喜欢使用strpos函数。 - Charles Yeung
@ Alexander.Plutov第二个你给我一个-1而不是问题? cmon需要2秒才能得到答案 google.com/... - Breezer
+1这是一种搜索简单字符串的可怕方式,但许多SO的访问者正在寻找任何方法来搜索他们自己的子字符串,并且提出建议是有帮助的。甚至OP也可能过于简单 - 让他知道他的替代方案。 - SamGoody
从技术上讲,问题是如何找到 话 不是子串。这实际上帮助了我,因为我可以使用正则表达式边界。替代品总是有用的。
答案为+1,@ plutov.by评论为-1,因为,strpos只是一次检查,同时regexp你可以在同一时间检查多个单词ex:preg_match(/ are | you | not /) - albanx


这是一个小实用函数,在这种情况下很有用

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

198



@RobinvanBaalen实际上,它可以提高代码的可读性。此外,downvotes应该是(非常)坏的答案,而不是“中性”答案。 - Xaqq
@RobinvanBaalen函数几乎是为了可读性而定义的(传达你正在做的事情的想法)。比较哪个更具可读性: if ($email->contains("@") && $email->endsWith(".com)) { ... 要么 if (strpos($email, "@") !== false && substr($email, -strlen(".com")) == ".com") { ... - Brandin
@RobinvanBaalen最终规则意味着被打破。否则人们就不会想出更新的创造性做事方式:)。另外,我不得不承认,我很难将想法包装在像martinfowler.com这样的东西上。猜猜正确的事情是自己尝试一下,找出哪种方法最方便。 - James P.
另一种观点:拥有一个可以轻松包装的实用程序功能可以帮助调试。此外,它还能为优秀的优化者带来呐喊,从而消除了生产服务中的这种开销。所以所有意见都有效点。 ;) - Tino
当然这很有用。你应该鼓励这一点。如果在PHP 100中有一种新的更快的方法来查找字符串位置会发生什么?你想改变你所谓的strpos的所有地方吗?或者你想只改变函数内的包含? - Cosmin


虽然这些答案中的大部分都会告诉您字符串中是否出现子字符串,但如果您正在寻找特定字符串,那通常不是您想要的 ,而不是

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

  • “区域”开头的“是”
  • “野兔”结束时的“是”
  • 在“票价”中间的“是”

减轻这种情况的一种方法是使用与之相配的正则表达式 字边界 (\b):

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

这种方法没有上面提到的相同的误报,但它确实有一些自己的边缘情况。单词边界匹配非单词字符(\W),这将是任何不是 a-zA-Z0-9, 要么 _。这意味着数字和下划线将被计为单词字符,这样的场景将失败:

  • “你在想什么?”中的“是”?
  • “是谁”中的“大声笑”,那些是4?

如果你想要比这更准确的东西,你将不得不开始进行英语语法语法分析,这是一个非常大的蠕虫(并假设正确使用语法,无论如何,这并不总是给定)。


113



这应该是规范的答案。因为我们正在寻找 话并不是 子,正则表达式是合适的。我还要补充一点 \b 匹配两件事 \W 没有,这使它很适合寻找 话 在一个字符串中:它匹配字符串的开头(^)和字符串结尾($) - code_monk
这不起作用: 3v4l.org/vPk2V - Jimbo
这应该是正确的答案..其余的答案会在“你关心的”字符串中找到“are”。正如@Dtest所提到的那样 - Robert Sinclair
@RobertSinclair那么糟糕吗?如果你问我“你关心的”字符串是否包含“是”这个词,我会说“是”。单词“are”显然是该字符串的子串。这是一个单独的问题“”“是”是“字符串中的一个词”你关心“”“”。 - Paulpro
@Paulpro尽管OP没有指定$ a是一个短语,我很确定它是隐含的。所以他的问题是如何检测短语中的单词。如果一个Word里面包含一个Word,那么我认为这个词往往不相关。 - Robert Sinclair


要确定字符串是否包含另一个字符串,您可以使用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,如果您执行了此操作 == 比较那不起作用,你需要做一个 ===

一个 == sign是一个比较,并测试左边的变量/ expression / constant是否与右边的变量/ expression / constant具有相同的值。

一个 === sign是比较两个变量/ expresions / constants是否相等 AND具有相同的类型 - 即两者都是字符串或两者都是整数。


93



引用来源? maxi-pedia.com/string+contains+substring+PHP - btk


运用 strstr() 要么 stristr() 如果您的搜索应该不区分大小写将是另一种选择。


57



关于的一个注释 php.net/manual/en/function.strstr.php page:注意:如果您只想确定特定针是否出现在haystack中,请使用更快且内存更少的内存密集型函数strpos()。 - Jo Smo
@tastro这是否有任何声誉良好的基准? - Wayne Whitty
这可能会慢一点,但恕我直言 strstr($a, 'are') 比丑陋更优雅 strpos($a, 'are') !== false。 PHP真的需要一个 str_contains() 功能。 - Paul Spiegel


看着 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.";
    }
?>

55





如果你想避免“假”和“真理”问题,你可以使用substr_count:

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

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


37





利用 不区分大小写 运用 stripos()

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

37





同意SamGoody和Lego Stormtroopr的评论。

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

其他布尔搜索方法的问题,如 strpos()preg_match()strstr() 要么 stristr() 

  1. 无法搜索多个单词
  2. 结果没有任何结果

基于PHP的PHP方法 矢量空间模型 和 tf-idf(术语频率 - 逆文档频率):

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

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

如果我们可以根据它们对字符串整体的代表性来对字符串中的术语进行加权, 我们可以通过最符合查询的结果来排序结果。

这是矢量空间模型的概念, 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()

NOTA BENE

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

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

  • 减少磁盘I / O.

  • 更快的索引和更快的搜索。

1.规范化

  • 将所有文本转换为小写

2.删除词汇

  • 消除文本中没有实际意义的词语(如'和','或','','for'等)

3.字典替换

  • 将词语替换为具有相同或相似含义的其他词语。 (例如:用'饥饿'代替'饥饿'和'饥饿'的例子)

  • 可以执行进一步的算法测量(滚雪球)以进一步将单词减少到其本质含义。

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

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

资源 


35