2660

Consider:

$a = 'How are you?';

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

Suppose I have the code above, what is the correct way to write the statement if ($a contains 'are')?

John Slegers
  • 38,420
  • 17
  • 182
  • 152
Charles Yeung
  • 36,649
  • 27
  • 83
  • 130

36 Answers36

7408

You can use the strpos() function which is used to find the occurrence of one string inside another one:

$a = 'How are you?';

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

Note that the use of !== false is deliberate (neither != false nor === true will return the desired result); strpos() returns either the offset at which the needle string begins in the haystack string, or the boolean false if the needle isn't found. Since 0 is a valid offset and 0 is "falsey", we can't use simpler constructs like !strpos($a, 'are').

Now with PHP 8 you can do this using str_contains:

if (str_contains('How are you', 'are')) { 
    echo 'true';
}

RFC

Dharman
  • 21,838
  • 18
  • 57
  • 107
codaddict
  • 410,890
  • 80
  • 476
  • 515
  • 176
    @DTest - well yes of course it will return true because the string contains 'are'. If you are looking specifically for the word ARE then you would need to do more checks like, for example, check if there is a character or a space before the A and after the E. – jsherk Nov 14 '12 at 21:35
  • 42
    Very good comments above! I never use != or ==, after all !== and === is best option (in my opinion) all aspect considered (speed, accuracy etc). – Melsi Dec 15 '12 at 12:28
  • 10
    @jsherk Why not regexes, then? Something like " are ". – Giulio Muscarello Jan 06 '13 at 15:48
  • 2
    best way is `if ((strpos($form_email,'@') === false) || (strpos($form_email,'.') === false)) { $error = 'Invalid email
    '; }`
    – erdomester Jan 08 '13 at 19:20
  • 3
    @Guiulio: Regex is slower :) If you only need to check if it exists, in any way ( so 'are' or 'care' doesnt matter), then use basic functions for better performance – Martijn Jul 17 '13 at 12:26
  • 6
    As for not catching 'care' and such things, it is better to check for (strpos(' ' . strtolower($a) . ' ', ' are ') !== false) – Wouter Sep 23 '13 at 14:26
  • 2
    I wanted to check if a string does *not* contain a word. I tried to change false to true `if (strpos($a,'are')!==true) {...}` but it does not work. Instead I am using now: `if(! (strpos($a,'are')!==false)) { ... }` which looks awkward. Anyone? – Avatar Dec 31 '13 at 07:32
  • 3
    @EchtEinfachTV that function always return false or the postion but never true – meda Feb 20 '14 at 16:27
  • 4
    @EchtEinfachTV try `strpos($a,'are')===false`. `===` is the complementary operator of `!==`. – Tino Feb 20 '14 at 21:13
  • 3
    @Melsi What speed got to do with the fact, whether you use compare with (`===`) or without (`==`) type checking? Do you suggest, that `===` is faster that `==`? I doubt so... – trejder Apr 09 '14 at 14:08
  • 23
    I tend to avoid this issue by always using `strpos($a, 'are') > -1` to test for true. From a debugging perspective, I find my brain wastes fewer clock cycles determining if the line is written correctly when I don't have to count contiguous equals signs. – equazcion May 06 '14 at 06:01
  • 6
    @Wouter Padding with spaces and searching for `" are "` is not the solution, as it's not necessarily followed by a space (eg. `" You are. "`) – minipif Nov 05 '14 at 00:37
  • 2
    @DTest is kinda right. I don't want to be "that guy" but either this answer is incomplete or the **question should be rephrased** to not specify it's looking for "words" ^^U – xDaizu Feb 01 '16 at 11:59
  • 3
    why not simply `if (strpos($a, 'are') > -1) {//found}else{//not found}` – LIGHT Mar 03 '17 at 17:33
  • 3
    I've landed on this specific answer hundreds of times in my career, and every time I read it, my brain hurts. Seeings as this question has been view 2.5 million times could we possibly change the example to something like `$subject = 'How are you?';$query = 'are';if (strpos($subject, $query) !== false)...`. No worries if not, the fact it has been viewed 2.5 million times is probably also a good reason not to change it. I'd also opt for `return true` rather than `echo 'true'` but I understand that is really starting to deviate from the question. – Djave Jun 09 '17 at 13:01
  • 3
    Yes, using '===' is faster than '==' because there is no type coercion necessary. – Mark Cross Dec 14 '17 at 11:16
  • 3
    Note, that because many frameworks agree this is dumb, most of them have helper functions available. For example, Laravel has `str_contains($a, 'are');` as seen here: https://laravel.com/docs/5.5/helpers#method-str-contains. – Tim Visée Jan 02 '18 at 08:58
  • 3
    If I get $1 everytime I visit this page just to copy paste this solution, I could have bought ramen noodles for a whole week – Ron Jan 12 '18 at 00:04
  • 1
    If you are interested in words rather than bytes, use [`grapheme_strpos()`](http://php.net/manual/en/function.grapheme-strpos.php). Or, if you really can not use [Intl](http://php.net/manual/en/book.intl.php), use [`mb_strpos()`](http://php.net/manual/en/function.mb-strpos.php) instead. – Code4R7 Feb 26 '18 at 19:37
  • 1
    If you're still on PHP 7 but want to start using the PHP 8 function, you can use this polyfill: `if (!function_exists('str_contains')) { function str_contains($haystack, $needle) { return $needle !== '' && mb_strpos($haystack, $needle) !== false; } }` -- taken from [this php.net comment](https://www.php.net/manual/en/function.str-contains.php#125977); based on Laravel. – squarecandy Apr 12 '21 at 16:13
  • So the advantage of str_contains is just that it is easier to read? – baptx May 21 '21 at 21:04
686

You could use regular expressions as it's better for word matching compared to strpos, as mentioned by other users. A strpos check for are will also return true for strings such as: fare, care, stare, etc. These unintended matches can simply be avoided in regular expression by using word boundaries.

A simple match for are could look something like this:

$a = 'How are you?';

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

On the performance side, strpos is about three times faster. When I did one million compares at once, it took preg_match 1.5 seconds to finish and for strpos it took 0.5 seconds.

Edit: In order to search any part of the string, not just word by word, I would recommend using a regular expression like

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

The i at the end of regular expression changes regular expression to be case-insensitive, if you do not want that, you can leave it out.

Now, this can be quite problematic in some cases as the $search string isn't sanitized in any way, I mean, it might not pass the check in some cases as if $search is a user input they can add some string that might behave like some different regular expression...

Also, here's a great tool for testing and seeing explanations of various regular expressions Regex101

To combine both sets of functionality into a single multi-purpose function (including with selectable case sensitivity), you could use something like this:

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.
}

One more thing to take in mind, is that \b will not work in different languages other than english.

The explanation for this and the solution is taken from here:

\b represents the beginning or end of a word (Word Boundary). This regex would match apple in an apple pie, but wouldn’t match apple in pineapple, applecarts or bakeapples.

How about “café”? How can we extract the word “café” in regex? Actually, \bcafé\b wouldn’t work. Why? Because “café” contains non-ASCII character: é. \b can’t be simply used with Unicode such as समुद्र, 감사, месяц and .

When you want to extract Unicode characters, you should directly define characters which represent word boundaries.

The answer: (?<=[\s,.:;"']|^)UNICODE_WORD(?=[\s,.:;"']|$)

So in order to use the answer in PHP, you can use this function:

function contains($str, array $arr) {
    // Works in Hebrew and any other unicode characters
    // Thanks https://medium.com/@shiba1014/regex-word-boundaries-with-unicode-207794f6e7ed
    // Thanks https://www.phpliveregex.com/
    if (preg_match('/(?<=[\s,.:;"\']|^)' . $word . '(?=[\s,.:;"\']|$)/', $str)) return true;
}

And if you want to search for array of words, you can use this:

function arrayContainsWord($str, array $arr)
{
    foreach ($arr as $word) {
        // Works in Hebrew and any other unicode characters
        // Thanks https://medium.com/@shiba1014/regex-word-boundaries-with-unicode-207794f6e7ed
        // Thanks https://www.phpliveregex.com/
        if (preg_match('/(?<=[\s,.:;"\']|^)' . $word . '(?=[\s,.:;"\']|$)/', $str)) return true;
    }
    return false;
}

As of PHP 8.0.0 you can now use str_contains

<?php
    if (str_contains('abc', '')) {
        echo "Checking the existence of the empty string will always 
        return true";
    }
Maarten
  • 174
  • 17
Breezer
  • 9,844
  • 6
  • 27
  • 47
  • 1
    I doubt it. The docs state `int preg_match ( string $pattern , string $subject [, array &$matches [, int $flags = 0 [, int $offset = 0 ]]] )`. – jwueller Dec 06 '10 at 13:20
  • 1
    I would argue that i find it to be the total opposite, it's bad to use it for complicated operation if an alternative is present, but for really simple word matching it's great you can set different delimiters to make it case insensitive and what not – Breezer Dec 06 '10 at 13:29
  • 10
    @Alexander.Plutov second of all you're giving me a -1 and not the question ? cmon it takes 2 seconds to google the answer http://www.google.com/search?btnG=1&pws=0&q=find+word+in+string+php – Breezer Dec 06 '10 at 14:03
  • 65
    +1 Its a horrible way to search for a simple string, but many visitors to SO are looking for any way to search for any of their own substrings, and it is helpful that the suggestion has been brought up. Even the OP might have oversimplified - let him know of his alternatives. – SamGoody Nov 09 '11 at 09:53
  • 77
    Technically, the question asks how to find **words** not a substring. This actually helped me as I can use this with regex word boundries. Alternatives are always useful. –  Aug 20 '13 at 05:57
  • 1
    Do not use preg_match() if you only want to check if one string is contained in another string. Use strpos() or strstr() instead as they will be faster. – Vinod Joshi Apr 05 '14 at 11:14
  • @LegoStormtroopr While the question does ask that, this answer doesn't actually show a solution which checks only for whole words. If would have been a much better answer if it had. – Mr Lister Apr 14 '14 at 08:41
  • 15
    +1 for the answer and -1 to the @plutov.by comment because , strpos is just a single check meanwhile regexp you can check many words in the same time ex: preg_match(/are|you|not/) – albanx Nov 05 '14 at 17:05
  • 5
    Regular Expressions should be the last resort method. Their use in trivial tasks should be discouraged. I insist on this from the height of many years of digging bad code. – yentsun Feb 18 '15 at 14:38
  • 2
    This comment is totally lost in nowhere but anyway: `preg_match` works when you need to check the result of `json` request (does it contain `error` word?) before `json_decode`. `strpos` didn't work for me. – Jasom Dotnet Oct 27 '15 at 08:33
  • 2
    If `$a='Computer hardware'`, I want it to return `false` when looking for `are`. Nevertheless, in this case it returns true. How do you do it to only look for entire words??? – Pathros Aug 10 '16 at 17:13
  • 3
    The regular expression should be `'/\bare\b/'`. The `\b` is a marker for word boundary, so this regular expression won't match 'hardware'. – Michael Oct 21 '16 at 18:25
  • Using a regex to do a simple operation is overkill. Use strpos instead – Spotlight Mar 16 '17 at 16:13
  • this strpos() is not working for mw sometimes this answer helps +1 – Asad Ullah Feb 05 '20 at 12:03
  • was looking for this alternative. really helpful – MaXi32 Nov 12 '20 at 14:18
  • Please be wary that `str_contains()` will return true on partial matches also (`ox` will match `fox`). https://3v4l.org/ARJqh – dearsina Mar 06 '21 at 10:36
282

Here is a little utility function that is useful in situations like this

// returns true if $needle is a substring of $haystack
function contains($needle, $haystack)
{
    return strpos($haystack, $needle) !== false;
}
ejunker
  • 10,386
  • 11
  • 37
  • 40
  • 1
    Might be in it's place it a utility class though and would improve readability. – James P. Jun 02 '13 at 17:58
  • 75
    @RobinvanBaalen Actually, it can improves code readability. Also, downvotes are supposed to be for (very) bad answers, not for "neutral" ones. – Xaqq Jul 09 '13 at 08:56
  • 1
    @Xaqq In my opinion, it's very bad to write functions that don't actually do anything else than improve readability. Therefore the -1. – Robin van Baalen Jul 09 '13 at 17:14
  • 38
    @RobinvanBaalen functions are nearly by definition for readability (to communicate the idea of what you're doing). Compare which is more readable: `if ($email->contains("@") && $email->endsWith(".com)) { ...` or `if (strpos($email, "@") !== false && substr($email, -strlen(".com")) == ".com") { ...` – Brandin Jul 25 '13 at 12:12
  • 2
    @RobinvanBaalen _"it's very bad to write functions that don't actually do anything else than improve readability"_ It depends. This is not the best of examples but if you're maintaining someone else's code it can be helpful. – James P. Aug 19 '13 at 04:40
  • @JamesPoulson don't forget to quote the 'in my opinion' part please. It is after all just my opinion and I'm never suggesting that it's a golden rule. That being said, you are completely right that there might be some useful cases for this. But even then, in my opinion, it's still bad practice. – Robin van Baalen Aug 21 '13 at 18:37
  • 3
    @RobinvanBaalen in the end rules are meant to be broken. Otherwise people wouldn't come up with newer inventive ways of doing things :) . Plus have to admit I have trouble wrapping the mind around stuff like on martinfowler.com. Guess the right thing to do is to try things out yourself and find out what approaches are the most convenient. – James P. Aug 22 '13 at 01:43
  • 6
    Another opinion: Having an utility function which you can easily wrap can help debugging. Also it loundens the cry for good optimizers which eliminate such overhead in production services. So all opinions have valid points. ;) – Tino Feb 20 '14 at 21:09
  • For those of us also writing C# this function is a nice addition. Note: it needs to be coded as return (strpos($haystack, $needle) !== false); – user610342 Oct 22 '14 at 13:08
  • You never know if the needle comes before or after the haystace. This helper function changes needle to the more common position. +1 – Bryan Jan 09 '15 at 01:12
  • Like many before me have said this improves readability, but lets say later on in your project you realize this function is returning false all over the place. Maybe because a word started with a capital letter when it normally started with a – JoeMoe1984 Jan 29 '15 at 18:40
  • 19
    Of course this is usefull. You should encourage this. What happens if in PHP 100 there is a new and faster way to find string locations ? Do you want to change all your places where you call strpos ? Or do you want to change only the contains within the function ?? – Cosmin Jun 17 '15 at 09:44
155

While most of these answers will tell you if a substring appears in your string, that's usually not what you want if you're looking for a particular word, and not a substring.

What's the difference? Substrings can appear within other words:

  • The "are" at the beginning of "area"
  • The "are" at the end of "hare"
  • The "are" in the middle of "fares"

One way to mitigate this would be to use a regular expression coupled with word boundaries (\b):

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

This method doesn't have the same false positives noted above, but it does have some edge cases of its own. Word boundaries match on non-word characters (\W), which are going to be anything that isn't a-z, A-Z, 0-9, or _. That means digits and underscores are going to be counted as word characters and scenarios like this will fail:

  • The "are" in "What _are_ you thinking?"
  • The "are" in "lol u dunno wut those are4?"

If you want anything more accurate than this, you'll have to start doing English language syntax parsing, and that's a pretty big can of worms (and assumes proper use of syntax, anyway, which isn't always a given).

Carlos Campderrós
  • 19,907
  • 10
  • 48
  • 56
FtDRbwLXw6
  • 25,206
  • 12
  • 61
  • 102
  • 24
    this should be the canonical answer. Because we're looking for _words_ and not _substrings_, regex is appropriate. I'll also add that `\b` matches two things that `\W` doesn't, which makes it great for finding _words_ in a string: It matches beginning of string (`^`) and end of string (`$`) – code_monk Oct 12 '14 at 02:09
  • 1
    this should be the correct answer.. the rest of the answers will find "are" in a string like "do you care".. As mentioned by @Dtest – Robert Sinclair Jun 30 '16 at 07:17
  • @RobertSinclair Is that so bad? If you asked me if the string "do you care" contains the word "are" I would say "yes". The word "are" is clearly a substring of that string. That's a separate question from """Is "are" one of the words in the string "do you care"""". – Paul Jul 05 '16 at 19:15
  • @Paulpro Eventhough OP didn't specify the $a is a phrase, I'm pretty sure it was implied. So his question was how to detect the Word inside the Phrase. Not if a Word contains a Word inside of it, which I would assume would be irrelevant more often than not. – Robert Sinclair Jul 06 '16 at 22:08
  • @Jimbo it does works, you're just missing the `\\` https://3v4l.org/ZRpYi – MetalWeirdo Jul 24 '18 at 09:17
143

To determine whether a string contains another string you can use the PHP function 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";
}

?>

CAUTION:

If the needle you are searching for is at the beginning of the haystack it will return position 0, if you do a == compare that will not work, you will need to do a ===

A == sign is a comparison and tests whether the variable / expression / constant to the left has the same value as the variable / expression / constant to the right.

A === sign is a comparison to see whether two variables / expresions / constants are equal AND have the same type - i.e. both are strings or both are integers.

nik7
  • 747
  • 2
  • 8
  • 17
Jose Vega
  • 9,800
  • 7
  • 37
  • 56
73

Look at 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.";
    }
?>
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Haim Evgi
  • 114,996
  • 43
  • 205
  • 218
64

Using strstr() or stristr() if your search should be case insensitive would be another option.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
glutorange
  • 1,004
  • 1
  • 10
  • 17
  • 9
    A note on the http://php.net/manual/en/function.strstr.php page: Note: If you only want to determine if a particular needle occurs within haystack, use the faster and less memory intensive function strpos() instead. – Jo Smo Feb 08 '14 at 17:49
  • @tastro Are there any reputable benchmarks on this? – Wayne Whitty Jun 17 '14 at 10:26
  • This might be slower, but IMHO `strstr($a, 'are')` is much more elegant than the ugly `strpos($a, 'are') !== false`. PHP really needs a `str_contains()` function. – Paul Spiegel Mar 15 '18 at 10:57
  • It blows my mind that this is not the accepted answer – kurdtpage Jan 15 '20 at 03:03
52

Peer to SamGoody and Lego Stormtroopr comments.

If you are looking for a PHP algorithm to rank search results based on proximity/relevance of multiple words here comes a quick and easy way of generating search results with PHP only:

Issues with the other boolean search methods such as strpos(), preg_match(), strstr() or stristr()

  1. can't search for multiple words
  2. results are unranked

PHP method based on Vector Space Model and tf-idf (term frequency–inverse document frequency):

It sounds difficult but is surprisingly easy.

If we want to search for multiple words in a string the core problem is how we assign a weight to each one of them?

If we could weight the terms in a string based on how representative they are of the string as a whole, we could order our results by the ones that best match the query.

This is the idea of the vector space model, not far from how SQL full-text search works:

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;
}

CASE 1

$query = 'are';

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

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

RESULT

Array
(
    [1] => 0.52832083357372
)

CASE 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>';

RESULTS

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

CASE 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>';

RESULTS

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

There are plenty of improvements to be made but the model provides a way of getting good results from natural queries, which don't have boolean operators such as strpos(), preg_match(), strstr() or stristr().

NOTA BENE

Optionally eliminating redundancy prior to search the words

  • thereby reducing index size and resulting in less storage requirement

  • less disk I/O

  • faster indexing and a consequently faster search.

1. Normalisation

  • Convert all text to lower case

2. Stopword elimination

  • Eliminate words from the text which carry no real meaning (like 'and', 'or', 'the', 'for', etc.)

3. Dictionary substitution

  • Replace words with others which have an identical or similar meaning. (ex:replace instances of 'hungrily' and 'hungry' with 'hunger')

  • Further algorithmic measures (snowball) may be performed to further reduce words to their essential meaning.

  • The replacement of colour names with their hexadecimal equivalents

  • The reduction of numeric values by reducing precision are other ways of normalising the text.

RESOURCES

Farzad Karimi
  • 701
  • 10
  • 25
RafaSashi
  • 14,170
  • 8
  • 71
  • 85
48

Make use of case-insensitve matching using stripos():

if (stripos($string,$stringToSearch) !== false) {
    echo 'true';
}
Amal Murali
  • 70,371
  • 17
  • 120
  • 139
Shankar Damodaran
  • 65,155
  • 42
  • 87
  • 120
41

If you want to avoid the "falsey" and "truthy" problem, you can use substr_count:

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

It's a bit slower than strpos but it avoids the comparison problems.

Alan Piralla
  • 1,178
  • 2
  • 10
  • 20
34
if (preg_match('/(are)/', $a)) {
   echo 'true';
}
Ifeanyi Amadi
  • 651
  • 4
  • 10
joan16v
  • 4,551
  • 2
  • 44
  • 45
  • 3
    I am getting the following warning: `WARNING preg_match(): Delimiter must not be alphanumeric or backslash` – Pathros Aug 10 '16 at 17:06
30

Another option is to use the strstr() function. Something like:

if (strlen(strstr($haystack,$needle))>0) {
// Needle Found
}

Point to note: The strstr() function is case-sensitive. For a case-insensitive search, use the stristr() function.

YashG99
  • 509
  • 9
  • 20
  • 1
    strstr() returns FALSE if the needle was not found. So a strlen is not necessary. – AKS Sep 11 '12 at 04:13
28

I'm a bit impressed that none of the answers here that used strpos, strstr and similar functions mentioned Multibyte String Functions yet (2015-05-08).

Basically, if you're having trouble finding words with characters specific to some languages, such as German, French, Portuguese, Spanish, etc. (e.g.: ä, é, ô, ç, º, ñ), you may want to precede the functions with mb_. Therefore, the accepted answer would use mb_strpos or mb_stripos (for case-insensitive matching) instead:

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

If you cannot guarantee that all your data is 100% in UTF-8, you may want to use the mb_ functions.

A good article to understand why is The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!) by Joel Spolsky.

Community
  • 1
  • 1
Armfoot
  • 4,137
  • 2
  • 39
  • 58
27

In PHP, the best way to verify if a string contains a certain substring, is to use a simple helper function like this:

function contains($haystack, $needle, $caseSensitive = false) {
    return $caseSensitive ?
            (strpos($haystack, $needle) === FALSE ? FALSE : TRUE):
            (stripos($haystack, $needle) === FALSE ? FALSE : TRUE);
}

Explanation:

  • strpos finds the position of the first occurrence of a case-sensitive substring in a string.
  • stripos finds the position of the first occurrence of a case-insensitive substring in a string.
  • myFunction($haystack, $needle) === FALSE ? FALSE : TRUE ensures that myFunction always returns a boolean and fixes unexpected behavior when the index of the substring is 0.
  • $caseSensitive ? A : B selects either strpos or stripos to do the work, depending on the value of $caseSensitive.

Output:

var_dump(contains('bare','are'));            // Outputs: bool(true)
var_dump(contains('stare', 'are'));          // Outputs: bool(true)
var_dump(contains('stare', 'Are'));          // Outputs: bool(true)
var_dump(contains('stare', 'Are', true));    // Outputs: bool(false)
var_dump(contains('hair', 'are'));           // Outputs: bool(false)
var_dump(contains('aren\'t', 'are'));        // Outputs: bool(true)
var_dump(contains('Aren\'t', 'are'));        // Outputs: bool(true)
var_dump(contains('Aren\'t', 'are', true));  // Outputs: bool(false)
var_dump(contains('aren\'t', 'Are'));        // Outputs: bool(true)
var_dump(contains('aren\'t', 'Are', true));  // Outputs: bool(false)
var_dump(contains('broad', 'are'));          // Outputs: bool(false)
var_dump(contains('border', 'are'));         // Outputs: bool(false)
John Slegers
  • 38,420
  • 17
  • 182
  • 152
24

You can use the strstr function:

$haystack = "I know programming";
$needle   = "know";
$flag = strstr($haystack, $needle);

if ($flag){

    echo "true";
}

Without using an inbuilt function:

$haystack  = "hello world";
$needle = "llo";

$i = $j = 0;

while (isset($needle[$i])) {
    while (isset($haystack[$j]) && ($needle[$i] != $haystack[$j])) {
        $j++;
        $i = 0;
    }
    if (!isset($haystack[$j])) {
        break;
    }
    $i++;
    $j++;

}
if (!isset($needle[$i])) {
    echo "YES";
}
else{
    echo "NO ";
}
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Arshid KV
  • 8,105
  • 3
  • 27
  • 32
  • 3
    [Crashes](http://stackoverflow.com/a/12804233/1677209) if you search the first word. – T30 Mar 21 '16 at 12:28
22

The function below also works and does not depend on any other function; it uses only native PHP string manipulation. Personally, I do not recommend this, but you can see how it works:

<?php

if (!function_exists('is_str_contain')) {
  function is_str_contain($string, $keyword)
  {
    if (empty($string) || empty($keyword)) return false;
    $keyword_first_char = $keyword[0];
    $keyword_length = strlen($keyword);
    $string_length = strlen($string);

    // case 1
    if ($string_length < $keyword_length) return false;

    // case 2
    if ($string_length == $keyword_length) {
      if ($string == $keyword) return true;
      else return false;
    }

    // case 3
    if ($keyword_length == 1) {
      for ($i = 0; $i < $string_length; $i++) {

        // Check if keyword's first char == string's first char
        if ($keyword_first_char == $string[$i]) {
          return true;
        }
      }
    }

    // case 4
    if ($keyword_length > 1) {
      for ($i = 0; $i < $string_length; $i++) {
        /*
        the remaining part of the string is equal or greater than the keyword
        */
        if (($string_length + 1 - $i) >= $keyword_length) {

          // Check if keyword's first char == string's first char
          if ($keyword_first_char == $string[$i]) {
            $match = 1;
            for ($j = 1; $j < $keyword_length; $j++) {
              if (($i + $j < $string_length) && $keyword[$j] == $string[$i + $j]) {
                $match++;
              }
              else {
                return false;
              }
            }

            if ($match == $keyword_length) {
              return true;
            }

            // end if first match found
          }

          // end if remaining part
        }
        else {
          return false;
        }

        // end for loop
      }

      // end case4
    }

    return false;
  }
}

Test:

var_dump(is_str_contain("test", "t")); //true
var_dump(is_str_contain("test", "")); //false
var_dump(is_str_contain("test", "test")); //true
var_dump(is_str_contain("test", "testa")); //flase
var_dump(is_str_contain("a----z", "a")); //true
var_dump(is_str_contain("a----z", "z")); //true 
var_dump(is_str_contain("mystringss", "strings")); //true 
Jason OOO
  • 3,447
  • 2
  • 21
  • 28
  • 13
    Could you please tell me why in the world you would use a function like this, when strpos is a perfectly viable solution?... – sg3s Sep 19 '13 at 14:05
  • 3
    @sg3s: you are totally right, however, strpos also based on something like that, also, I didn't posted it for rep just for sharing a bit of knowledge – Jason OOO Sep 19 '13 at 19:33
  • last var_dump is false – Sunny May 17 '15 at 21:29
  • 1
    @Sunny: it was typo: var_dump(is_str_contain("mystringss", "strings")); //true – Jason OOO May 18 '15 at 10:44
20

I had some trouble with this, and finally I chose to create my own solution. Without using regular expression engine:

function contains($text, $word)
{
    $found = false;
    $spaceArray = explode(' ', $text);

    $nonBreakingSpaceArray = explode(chr(160), $text);

    if (in_array($word, $spaceArray) ||
        in_array($word, $nonBreakingSpaceArray)
       ) {

        $found = true;
    }
    return $found;
 }

You may notice that the previous solutions are not an answer for the word being used as a prefix for another. In order to use your example:

$a = 'How are you?';
$b = "a skirt that flares from the waist";
$c = "are";

With the samples above, both $a and $b contains $c, but you may want your function to tell you that only $a contains $c.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Decebal
  • 1,161
  • 1
  • 19
  • 31
  • 1
    you probably meant: `$found = false` at the beginning – slownage Mar 04 '15 at 12:36
  • 1
    your function may not work if the word is linked with comma, question mark or dot. e.g. "what you see is what you get." and you want to determine if "get" is in the sentence. Notice the full stop next to "get". In this case, your function returns false. it is recommended to use regular expression or substr(I think it uses regular expression anyway) to search/replace strings. – lightbringer Apr 15 '15 at 06:12
  • @lightbringer you could not be more wrong with your recommendation, what does it mean for you "it is recommended" ? there is no supreme person that recommends or aproves. It's about the use of regular expression engine in php that is a blackhole in the language itself, you may want to try putting a regex match in a loop and benchmark the results. – Decebal Apr 16 '15 at 11:46
  • This answer is poorly demonstrated and fails with many extended scenarios. I don't see any benefit in entertaining this technique. Here is the refined custom function and iterated call: https://3v4l.org/E9dfD I have no interest in editing this wiki because I find it to be wasteful of researchers time. – mickmackusa Jul 24 '19 at 09:33
20

Lot of answers that use substr_count checks if the result is >0. But since the if statement considers zero the same as false, you can avoid that check and write directly:

if (substr_count($a, 'are')) {

To check if not present, add the ! operator:

if (!substr_count($a, 'are')) {
T30
  • 9,099
  • 5
  • 42
  • 56
18

Another option to finding the occurrence of a word from a string using strstr() and stristr() is like the following:

<?php
    $a = 'How are you?';
    if (strstr($a,'are'))  // Case sensitive
        echo 'true';
    if (stristr($a,'are'))  // Case insensitive
        echo 'true';
?>
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Sadikhasan
  • 17,212
  • 19
  • 72
  • 111
17

It can be done in three different ways:

 $a = 'How are you?';

1- stristr()

 if (strlen(stristr($a,"are"))>0) {
    echo "true"; // are Found
 } 

2- strpos()

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

3- preg_match()

 if( preg_match("are",$a) === 1) {
   echo "true"; // are Found
 }
Ronak Shah
  • 286,338
  • 16
  • 97
  • 143
Shashank Singh
  • 1,210
  • 12
  • 21
14

The short-hand version

$result = false!==strpos($a, 'are');
KsaR
  • 488
  • 6
  • 16
Somwang Souksavatd
  • 3,974
  • 26
  • 28
  • 5
    While this code snippet may solve the question, [including an explanation](http://meta.stackexchange.com/questions/114762/explaining-entirely-code-based-answers) really helps to improve the quality of your post. Remember that you are answering the question for readers in the future, and those people might not know the reasons for your code suggestion. – Bono Mar 13 '15 at 13:23
14

In order to find a 'word', rather than the occurrence of a series of letters that could in fact be a part of another word, the following would be a good solution.

$string = 'How are you?';
$array = explode(" ", $string);

if (in_array('are', $array) ) {
    echo 'Found the word';
}
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
DJC
  • 1,167
  • 1
  • 13
  • 32
13

You should use case Insensitive format,so if the entered value is in small or caps it wont matter.

<?php
$grass = "This is pratik joshi";
$needle = "pratik";
if (stripos($grass,$needle) !== false) { 

 /*If i EXCLUDE : !== false then if string is found at 0th location, 
   still it will say STRING NOT FOUND as it will return '0' and it      
   will goto else and will say NOT Found though it is found at 0th location.*/
    echo 'Contains word';
}else{
    echo "does NOT contain word";
}
?>

Here stripos finds needle in heystack without considering case (small/caps).

PHPCode Sample with output

Pratik
  • 10,715
  • 5
  • 33
  • 69
13

Maybe you could use something like this:

<?php
    findWord('Test all OK');

    function findWord($text) {
        if (strstr($text, 'ok')) {
            echo 'Found a word';
        }
        else
        {
            echo 'Did not find a word';
        }
    }
?>
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Mathias Stavrou
  • 750
  • 1
  • 7
  • 16
12

Do not use preg_match() if you only want to check if one string is contained in another string. Use strpos() or strstr() instead as they will be faster. (http://in2.php.net/preg_match)

if (strpos($text, 'string_name') !== false){
   echo 'get the string';
}
guillaumepotier
  • 6,893
  • 8
  • 40
  • 70
Vinod Joshi
  • 7,094
  • 46
  • 49
12

If you want to check if the string contains several specifics words, you can do:

$badWords = array("dette", "capitale", "rembourser", "ivoire", "mandat");

$string = "a string with the word ivoire";

$matchFound = preg_match_all("/\b(" . implode($badWords,"|") . ")\b/i", $string, $matches);

if ($matchFound) {
    echo "a bad word has been found";
}
else {
    echo "your string is okay";
}

This is useful to avoid spam when sending emails for example.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Julien
  • 2,535
  • 6
  • 31
  • 56
10

The strpos function works fine, but if you want to do case-insensitive checking for a word in a paragraph then you can make use of the stripos function of PHP.

For example,

$result = stripos("I love PHP, I love PHP too!", "php");
if ($result === false) {
    // Word does not exist
}
else {
    // Word exists
}

Find the position of the first occurrence of a case-insensitive substring in a string.

If the word doesn't exist in the string then it will return false else it will return the position of the word.

Akshay Khale
  • 7,087
  • 7
  • 43
  • 51
9

You need to use identical/not identical operators because strpos can return 0 as it's index value. If you like ternary operators, consider using the following (seems a little backwards I'll admit):

echo FALSE === strpos($a,'are') ? 'false': 'true';
John Slegers
  • 38,420
  • 17
  • 182
  • 152
Shapeshifter
  • 483
  • 6
  • 11
8

Check if string contains specific words?

This means the string has to be resolved into words (see note below).

One way to do this and to specify the separators is using preg_split (doc):

<?php

function contains_word($str, $word) {
  // split string into words
  // separators are substrings of at least one non-word character
  $arr = preg_split('/\W+/', $str, NULL, PREG_SPLIT_NO_EMPTY);

  // now the words can be examined each
  foreach ($arr as $value) {
    if ($value === $word) {
      return true;
    }
  }
  return false;
}

function test($str, $word) {
  if (contains_word($str, $word)) {
    echo "string '" . $str . "' contains word '" . $word . "'\n";
  } else {
    echo "string '" . $str . "' does not contain word '" . $word . "'\n" ;
  }
}

$a = 'How are you?';

test($a, 'are');
test($a, 'ar');
test($a, 'hare');

?>

A run gives

$ php -f test.php                   
string 'How are you?' contains word 'are' 
string 'How are you?' does not contain word 'ar'
string 'How are you?' does not contain word 'hare'

Note: Here we do not mean word for every sequence of symbols.

A practical definition of word is in the sense the PCRE regular expression engine, where words are substrings consisting of word characters only, being separated by non-word characters.

A "word" character is any letter or digit or the underscore character, that is, any character which can be part of a Perl " word ". The definition of letters and digits is controlled by PCRE's character tables, and may vary if locale-specific matching is taking place (..)

mvw
  • 4,845
  • 1
  • 23
  • 32
8

Use:

$text = 'This is a test';
echo substr_count($text, 'is'); // 2

// So if you want to check if is exists in the text just put
// in a condition like this:
if (substr_count($text, 'is') > 0) {
    echo "is exists";
}
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Kamaro Lambert
  • 751
  • 1
  • 7
  • 8
7

Another solution for a specific string:

$subject = 'How are you?';
$pattern = '/are/';
preg_match($pattern, $subject, $match);
if ($match[0] == 'are') {
    echo true;
}

You can also use strpos() function.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
devpro
  • 15,966
  • 3
  • 25
  • 38
7

You can also use built-in functions strchr() and strrchr() and extensions for multibyte strings mb_strchr() and mb_strrchr(). These functions return parts of strings, and FALSE if nothing is found.

  • strchr() - Find the first occurrence of a string (is an alias of strstr()).
  • strrchr() - Find the last occurrence of a character in a string.
6

A string can be checked with the below function:

function either_String_existor_not($str, $character) {
    return strpos($str, $character) !== false;
}
nik7
  • 747
  • 2
  • 8
  • 17
M Razwan
  • 247
  • 3
  • 11
6

I think that a good idea is to use mb_stpos:

$haystack = 'How are you?';
$needle = 'are';

if (mb_strpos($haystack, $needle) !== false) {

    echo 'true';
}

Because this solution is case sensitive and safe for all Unicode characters.


But you can also do it like this (sauch response was not yet):

if (count(explode($needle, $haystack)) > 1) {

    echo 'true';
}

This solution is also case sensitive and safe for Unicode characters.

In addition you do not use the negation in the expression, which increases the readability of the code.


Here is other solution using function:

function isContainsStr($haystack, $needle) {

    return count(explode($needle, $haystack)) > 1;
}

if (isContainsStr($haystack, $needle)) {

    echo 'true';
}
simhumileco
  • 21,911
  • 14
  • 106
  • 90
5

Use:

$a = 'How are you?';
if (mb_strpos($a, 'are')) {
    echo 'true';
}

It performs a multi-byte safe strpos() operation.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Mindexperiment
  • 137
  • 1
  • 9
  • 1
    This is not a good answer. If the search string will be at the begin of the searched string, then the function `mb_strpos(...)` return zero, which evolves into false. – simhumileco Feb 07 '17 at 13:07
5

A simpler option:

return ( ! empty($a) && strpos($a, 'are'))? true : false;
ShirleyCC
  • 675
  • 8
  • 8