Using an array as needles in strpos [duplicate]
Asked Answered
K

16

110

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

Kenti answered 8/6, 2011 at 20:4 Comment(0)
J
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
Jochebed answered 9/2, 2012 at 23:32 Comment(11)
@Arnaud, what is your suggested implement?Jochebed
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 ?Chi
Thanks @Chi for the feature suggestion! I totally agree with your suggestion importance and have updated my answer with improved code example.Jochebed
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.Chi
@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.Jochebed
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.Chi
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.Jochebed
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.Ferreous
Note that stripos() can be used inside this function to make the whole thing case insensitive.Doody
you can get a slight performance boost here by simply doing if (!$chr) return false;Ingemar
There is a typo on this line if (strposa($string, $array, 1))Daniels
C
93

str_replace is considerably faster.

$find_letters = array('a', 'c', 'd');
$string = 'abcdefg';
$match = (str_replace($find_letters, '', $string) != $string);
Cladophyll answered 18/2, 2017 at 6:10 Comment(1)
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.Ackley
U
21

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 
Unclose answered 8/6, 2011 at 20:8 Comment(1)
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?Epileptic
D
10

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.

Dogeared answered 19/9, 2017 at 6:49 Comment(1)
This worked perfectly for me since i was looking my array contained sub-strings. I was saved from writing sql command like"%$string%"Centiare
E
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.

Eweneck answered 8/6, 2011 at 20:7 Comment(2)
shouldn't it be !== flase ?Inalienable
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. !== falseBeare
H
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
}
Holds answered 8/6, 2011 at 20:18 Comment(1)
Incredible answer - MUCH faster execution than multiple strpos(), e.g., if (strpos($string, "a") !== false && strpos($string, "c") !== false && strpos($string, "d") !== false)Catrinacatriona
C
4

This expression searches for all letters:

count(array_filter( 
    array_map("strpos", array_fill(0, count($letters), $str), $letters),
"is_int")) == count($letters)
Commoner answered 8/6, 2011 at 20:16 Comment(0)
N
4

You can try this:

function in_array_strpos($word, $array){

foreach($array as $a){

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

return false;
}
Nielson answered 18/4, 2016 at 4:5 Comment(0)
C
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!';
}
Catrinacatriona answered 6/1, 2017 at 17:41 Comment(0)
I
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.

Ingemar answered 27/4, 2018 at 3:16 Comment(0)
B
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
   }
Briannabrianne answered 2/6, 2021 at 12:4 Comment(0)
V
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.

Vanegas answered 8/6, 2011 at 20:46 Comment(0)
M
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));
Misuse answered 4/11, 2016 at 21:20 Comment(0)
A
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;
}
Annapurna answered 14/11, 2017 at 22:15 Comment(0)
P
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;
}
Pickford answered 15/5, 2018 at 16:57 Comment(0)
D
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

Disarticulate answered 1/1, 2021 at 18:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.