108

How do you use the strpos for an array of needles when searching a string? For example:

$find_letters = array('a', 'c', 'd');
$string = 'abcdefg';

if(strpos($string, $find_letters) !== false)
{
    echo 'All the letters are found in the string!';
}

Because when using this, it wouldn't work, it would be good if there was something like this

MacMac
  • 34,294
  • 55
  • 151
  • 222

16 Answers16

159

@Dave an updated snippet from http://www.php.net/manual/en/function.strpos.php#107351

function strposa($haystack, $needles=array(), $offset=0) {
        $chr = array();
        foreach($needles as $needle) {
                $res = strpos($haystack, $needle, $offset);
                if ($res !== false) $chr[$needle] = $res;
        }
        if(empty($chr)) return false;
        return min($chr);
}

How to use:

$string = 'Whis string contains word "cheese" and "tea".';
$array  = array('burger', 'melon', 'cheese', 'milk');

if (strposa($string, $array, 1)) {
    echo 'true';
} else {
    echo 'false';
}

will return true, because of array "cheese".

Update: Improved code with stop when the first of the needles is found:

function strposa(string $haystack, array $needles, int $offset = 0): bool 
{
    foreach($needles as $needle) {
        if(strpos($haystack, $needle, $offset) !== false) {
            return true; // stop on first true result
        }
    }

    return false;
}
$string = 'This string contains word "cheese" and "tea".';
$array  = ['burger', 'melon', 'cheese', 'milk'];
var_dump(strposa($string, $array)); // will return true, since "cheese" has been found
Community
  • 1
  • 1
Binyamin
  • 7,493
  • 10
  • 60
  • 82
  • 1
    @Arnaud, what is your suggested implement? – Binyamin Sep 10 '13 at 05:51
  • 5
    I'm not sure, but maybe we could advance in the string from $offset, and stop when the first of the needles is found. Think about a big text full of "a". Take $needles = [a, b]. Your function `strposa` will run through all of the text, but it is not necessary ! Am I understandable ? – Arnaud Sep 10 '13 at 12:41
  • Thanks @Arnaud for the feature suggestion! I totally agree with your suggestion importance and have updated my answer with improved code example. – Binyamin Sep 10 '13 at 20:16
  • This is not exactly what I wanted to say, because with your new function $needles = [b, a] has yet a problem, and in addition the function no longer returns the position of the first occurrence. Let's me explain a little more. Assume that the string is "ABCDEF", and the needles are C and F. What we could do is running through the string : A, B... C ! We detect C, so we stop here and we can return the position of the first occurrence of a needle, which is 2. It could work with more than single-character strings, but I've not thought about the exact implementation. – Arnaud Sep 10 '13 at 23:24
  • @Arnaud, it is how it exactly works now. `foreach` will be stopped on `array` "cheese" and will not check "milk" since have already found one valid result. I tried the implementation also with `if(!empty($res)) break;`, but saw it working well also in this way. Check it by yourself by adding `$res = strpos($haystack, $query, 1); if(!empty($res)) break;` in `foreach`. – Binyamin Sep 11 '13 at 05:08
  • No, that's not what I wanted to say. Imagine in your example that after "tea", you have 10000000 characters. With your method, you search 'burger' until the end of the string, but this is not necessary. – Arnaud Sep 11 '13 at 11:00
  • It is possible to split very long string and check each part separately and stop on part where founded query. There would be almost no benefit if the string is not very long or the query has not been found. The splitting must be done smart so that query **contains word** would return `true` (**This string contains** and **word "cheese" and "tea"** returns `false`, where additional part **contains word** returns `true` after escaping comma. Escape would help too. And finally it can lead to like [Google Search logic](https://support.google.com/websearch/answer/136861?hl=en&ref_topic=3081620). – Binyamin Sep 11 '13 at 18:57
  • 1
    I improved the code by changing `foreach($needle as $k => $query) { if(strpos($haystack, $query, $offset) !== false) return $k; }`, so it returns the key of the matching item for further handling. – James Cameron Dec 17 '14 at 16:47
  • Note that stripos() can be used inside this function to make the whole thing case insensitive. – Lorien Brune Jul 03 '17 at 04:47
  • you can get a slight performance boost here by simply doing `if (!$chr) return false;` – But those new buttons though.. Apr 27 '18 at 03:26
  • There is a typo on this line `if (strposa($string, $array, 1))` – Barnabas Jul 16 '22 at 21:12
91

str_replace is considerably faster.

$find_letters = array('a', 'c', 'd');
$string = 'abcdefg';
$match = (str_replace($find_letters, '', $string) != $string);
Leon
  • 1,073
  • 1
  • 8
  • 8
  • This might be faster for the array of letters as asked in the question. But if it is an array of phrases, then I think strpos will be fatser. – Sadee Nov 17 '21 at 15:10
20

The below code not only shows how to do it, but also puts it in an easy to use function moving forward. It was written by "jesda". (I found it online)

PHP Code:

<?php
/* strpos that takes an array of values to match against a string
 * note the stupid argument order (to match strpos)
 */
function strpos_arr($haystack, $needle) {
    if(!is_array($needle)) $needle = array($needle);
    foreach($needle as $what) {
        if(($pos = strpos($haystack, $what))!==false) return $pos;
    }
    return false;
}
?>

Usage:

$needle = array('something','nothing');
$haystack = "This is something";
echo strpos_arr($haystack, $needle); // Will echo True

$haystack = "This isn't anything";
echo strpos_arr($haystack, $needle); // Will echo False 
Dave
  • 28,833
  • 23
  • 113
  • 183
  • I believe this only returns the 1st position it finds. Any suggestions for how to tweak it to return the position of every needle in the haystack? – Chaya Cooper Sep 29 '14 at 20:47
9

The question, is the provided example just an "example" or exact what you looking for? There are many mixed answers here, and I dont understand the complexibility of the accepted one.

To find out if ANY content of the array of needles exists in the string, and quickly return true or false:

$string = 'abcdefg';

if(str_replace(array('a', 'c', 'd'), '', $string) != $string){
    echo 'at least one of the needles where found';
};

If, so, please give @Leon credit for that.

To find out if ALL values of the array of needles exists in the string, as in this case, all three 'a', 'b' and 'c' MUST be present, like you mention as your "for example"

echo 'All the letters are found in the string!';

Many answers here is out of that context, but I doubt that the intension of the question as you marked as resolved. E.g. The accepted answer is a needle of

$array  = array('burger', 'melon', 'cheese', 'milk');

What if all those words MUST be found in the string?

Then you try out some "not accepted answers" on this page.

Jonas Lundman
  • 1,390
  • 16
  • 18
  • This worked perfectly for me since i was looking my array contained sub-strings. I was saved from writing sql command like"%$string%" – Maurice Elagu Nov 02 '17 at 06:27
6

You can iterate through the array and set a "flag" value if strpos returns false.

$flag = false;
foreach ($find_letters as $letter)
{
    if (strpos($string, $letter) !== false)
    {
        $flag = true;
    }
}

Then check the value of $flag.

Lucas Bustamante
  • 15,821
  • 7
  • 92
  • 86
Evan Mulawski
  • 54,662
  • 15
  • 117
  • 144
  • 7
    shouldn't it be `!== flase` ? – Joe Huang Nov 19 '13 at 04:54
  • It should be !==false. Unless you break right after you set your flag to true. And then would have to interpret the flag as a Warning that a needle is not in the haystack. That means that what you are trying to achieve is to check that all your needles are in the haystack. Which is not the question. So.. yeah. !== false – Kevin Gagnon Mar 21 '16 at 21:21
5

If you just want to check if certain characters are actually in the string or not, use strtok:

$string = 'abcdefg';
if (strtok($string, 'acd') === $string) {
    // not found
} else {
    // found
}
netcoder
  • 66,435
  • 19
  • 125
  • 142
4

You can try this:

function in_array_strpos($word, $array){

foreach($array as $a){

    if (strpos($word,$a) !== false) {
        return true;
    }
}

return false;
}
Dr.jacky
  • 3,341
  • 6
  • 53
  • 91
Rajnesh Nadan
  • 91
  • 1
  • 1
4

This expression searches for all letters:

count(array_filter( 
    array_map("strpos", array_fill(0, count($letters), $str), $letters),
"is_int")) == count($letters)
mario
  • 144,265
  • 20
  • 237
  • 291
1

You can also try using strpbrk() for the negation (none of the letters have been found):

$find_letters = array('a', 'c', 'd');
$string = 'abcdefg';

if(strpbrk($string, implode($find_letters)) === false)
{
    echo 'None of these letters are found in the string!';
}
1

This is my approach. Iterate over characters in the string until a match is found. On a larger array of needles this will outperform the accepted answer because it doesn't need to check every needle to determine that a match has been found.

function strpos_array($haystack, $needles = [], $offset = 0) {
    for ($i = $offset, $len = strlen($haystack); $i < $len; $i++){
        if (in_array($haystack[$i],$needles)) {
            return $i;
        }
    }
    return false;
}

I benchmarked this against the accepted answer and with an array of more than 7 $needles this was dramatically faster.

1

If i just want to find out if any of the needles exist in the haystack, i use

reusable function

function strposar($arrayOfNeedles, $haystack){
  if (count(array_filter($arrayOfNeedles, function($needle) use($haystack){
     return strpos($haystack, $needle) !== false;
   })) > 0){
    return true;
  } else {
    return false;
  }
}

strposar($arrayOfNeedles, $haystack); //returns true/false

or lambda function

  if (count(array_filter($arrayOfNeedles, function($needle) use($haystack){
     return strpos($haystack, $needle) !== false;
   })) > 0){
     //found so do this
   } else {
     //not found do this instead
   }
Clint
  • 973
  • 7
  • 18
0

I'm writing a new answer which hopefully helps anyone looking for similar to what I am.

This works in the case of "I have multiple needles and I'm trying to use them to find a singled-out string". and this is the question I came across to find that.

    $i = 0;
    $found = array();
    while ($i < count($needle)) {
        $x = 0;
        while ($x < count($haystack)) {
            if (strpos($haystack[$x], $needle[$i]) !== false) {
                array_push($found, $haystack[$x]);
            }
            $x++;
        }
        $i++;
    }

    $found = array_count_values($found);

The array $found will contain a list of all the matching needles, the item of the array with the highest count value will be the string(s) you're looking for, you can get this with:

print_r(array_search(max($found), $found));
ConorReidd
  • 276
  • 5
  • 25
0

Reply to @binyamin and @Timo.. (not enough points to add a comment..) but the result doesn't contain the position..
The code below will return the actual position of the first element which is what strpos is intended to do. This is useful if you're expecting to find exactly 1 match.. If you're expecting to find multiple matches, then position of first found may be meaningless.

function strposa($haystack, $needle, $offset=0) {
    if(!is_array($needle)) $needle = array($needle);
    foreach($needle as $query) {
      $res=strpos($haystack, $query, $offset);
      if($res !== false) return $res; // stop on first true result
    }
    return false;
}
0

Just an upgrade from above answers

function strsearch($findme, $source){
    if(is_array($findme)){
        if(str_replace($findme, '', $source) != $source){
            return true;
        }
    }else{
        if(strpos($source,$findme)){
            return true;
        }
    }
    return false;
}
0

With the following code:

$flag = true;
foreach($find_letters as $letter)
    if(false===strpos($string, $letter)) {
        $flag = false; 
        break;
    }

Then check the value of $flag. If it is true, all letters have been found. If not, it's false.

hakre
  • 193,403
  • 52
  • 435
  • 836
0
<?php
$Words = array("hello","there","world");
$c = 0;

    $message = 'Hi hello';
     foreach ($Words as $word):
        $trial = stripos($message,$word);
        
        if($trial != true){
            $c++;
            echo 'Word '.$c.' didnt match <br> <br>';
        }else{
            $c++;
            echo 'Word '.$c.' matched <br> <br>';
        }
     endforeach;
     ?>

I used this kind of code to check for hello, It also Has a numbering feature. You can use this if you want to do content moderation practices in websites that need the user to type

Connell.O'Donnell
  • 3,603
  • 11
  • 27
  • 61