Find at least one needle in a haystack string, where an array of needles is supplied
Asked Answered
A

5

6

I have a function that takes a string (the haystack) and an array of strings (the needles) and returns true if at least one needle is a substring of the haystack. It didn't take much time or effort to write it, but I'm wondering if there's a PHP function that already does this.

function strstr_array_needle($haystack, $arrayNeedles){
    foreach($arrayNeedles as $needle){
        if(strstr($haystack, $needle)) return true;
    }
    return false;    
}
Actinozoan answered 21/12, 2011 at 21:41 Comment(2)
change strstr($haystack, $needle) to strpos($haystack, $needle) !== false...Commentary
The PHP documentation has an explicit note stating that strstr() should not be used to confirm the existence of a substring (for performance reasons, it is always more ideal to use strpos() for such an operation).Laser
R
9

just a suggestion...

function array_strpos($haystack, $needles)
{
    foreach($needles as $needle)
        if(strpos($haystack, $needle) !== false) return true;
    return false;
}
Retrogressive answered 21/12, 2011 at 21:44 Comment(2)
Thanks for your answer, any particular reason to use strpos rather than strstr?Actinozoan
@RichardLivingston, Hi, well you should, because strstr returns part of the string (also this behavior is different with PHP5.3), while strpos returns position (if found) or false (if not found), so that is possibly faster. From the documents If you only want to determine if a particular needle occurs within haystack, use the faster and less memory intensive function strpos() instead.. Cheers.Commentary
S
0

There's no single function that behaves as strstr_array_needle (the name is misleading; I'd expect it to return a substring of $haystack). There are other functions that could be used instead of a loop, but they don't have benefits and take more time. For example:

# iterates over entire array, though stops checking once a match is found
array_reduce($needles, 
    function($found, $needle) use ($haystack) {
        return $found || (strpos($haystack, $needle) !== false);
    }, 
    false);

# iterates over entire array and checks each needle, even if one is already found
(bool)array_filter($needles,
    function($needle) use ($haystack) {
        return strpos($haystack, $needle) !== false;
    });
Sphygmograph answered 21/12, 2011 at 23:54 Comment(0)
C
0

Here is a tested and working function:

<?php
function strpos_array($haystack, $needles, $offset = 0) {
    if (is_array($needles)) {
        foreach ($needles as $needle) {
            $pos = strpos_array($haystack, $needle);
            if ($pos !== false) {
                return $pos;
            }
        }
        return false;
    } else {
        return strpos($haystack, $needles, $offset);
    }
}
Cati answered 2/8, 2015 at 17:30 Comment(2)
Rather than using an if block, simply cast the $needles as an array in the foreach() signature: foreach ((array) $needles as $needle) { ...if you aren't going to apply type declarations to your function parameters.Laser
Oh, now I see that you are offering a recursive solution -- that might have been a good idea to mention when describing your script. I don't think the asker or most researchers will need to traverse an indeterminant number of levels in the needles array.Laser
L
0

Whether you need to return a boolean result or the first encountered match, use a breakable loop to eliminate useless cycles. If you are using an outdated/unsupported version of PHP, replace str_contains() with a strpos() !== false check.

Code: (Demo)

function findANeedle(string $haystack, array $needles) {
    foreach ($needles as $needle) {
        if (str_contains($haystack, $needle)) {
            return $needle;
        }
    }
    return null;
}

function hasANeedle(string $haystack, array $needles): bool {
    foreach ($needles as $needle) {
        if (str_contains($haystack, $needle)) {
            return true;
        }
    }
    return false;
}

$haystack = 'food fighters';
$needles = ['bar', 'foo'];

var_export(findANeedle($haystack, $needles));
echo "\n--\n";
var_export(hasANeedle($haystack, $needles));

Output:

'foo'
--
true
Laser answered 24/3 at 6:3 Comment(0)
L
-1

If you are just trying to determine which needles exist in the haystack, I suggest the array_intersect function.

Documentation from the PHP.net website

<?php
$array1 = array("a" => "green", "red", "blue");
$array2 = array("b" => "green", "yellow", "red");
$result = array_intersect($array1, $array2);
print_r($result);
?>

The above example will output:
Array
(
    [a] => green
    [0] => red
)

Basically, this will result in an array that shows all values that appear in both arrays. In your case, your code is returning true if any needle is found. The following code will do this using the array_intersect function, though if this is any simpler than Charles answer is debatable.

if(sizeof(array_intersect($hackstack, $arrayNeedles)) > 0) 
    return true; 
else 
    return false;

Again, I am not sure exactly what your code is trying to do, other than return true if any needle exists. If you can provide some context on what you want to achieve, there may be a better way.

Hope this helps.

Lebeau answered 21/12, 2011 at 22:34 Comment(1)
The haystack is not an array.Laser

© 2022 - 2024 — McMap. All rights reserved.