I am returning all the array where the stripos
function matches like this
$requestedservice = request('service');
$result_array = array_filter($allservicesname, function($item) use ($requestedservice) {
return (stripos($item, $requestedservice) !== false);
});
This only works for the first occurrence, e.g- if the haystack is Walk dance and rock
if the needle is Walk
it reutrns Walk dance and rock
, but if the needle is Walk rock
it does not return Walk dance and rock
. Why is this happening?
Is there a way to find for all occurrences, so that, it matches the haystack Walk dance and rock
with the needle Walk rock
?
And also if the needle is Walk run
it should not match Walk dance and rock
, this is kind of normal use case
It appears you will be able to achieve your desired filtration with a loop of case-insensitive keyword checks.
Code: (Demo)
$allservicesname=['dance','Walk rock','Walk dance and rock','Walk']; // array of haystacks
$requestedservice='walk rock'; // string of needles
$result_array=array_filter($allservicesname,function($string)use($requestedservice){
foreach(explode(' ',$requestedservice) as $keyword){
if(stripos($string,$keyword)===false){
return false;
}
}
return true;
});
var_export($result_array);
Output:
array (
1 => 'Walk rock',
2 => 'Walk dance and rock',
)
Notice the original keys are preserved in the output array. Also, I should mention that the keywords can appear in any order and maintain accuracy.
Alternatively, if you are not scared off by the idea of regex, preg_grep()
can concisely perform this task. It is the function that is designed to filter arrays using regex on each element.
Code: (Demo) (Regex Pattern Demo)
$allservicesname=['Walk dance and rock walk','dance','walk','rock and walk','sidewalk and rockwall']; // array of haystacks
$requestedservice='walk rock'; // string of needles
$pattern='/(?=.*\Q'.str_replace(' ','\E)(?=.*\Q',$requestedservice).'\E)/i'; // with literal substring matching, no wordboundaries
//$pattern='/(?=.*\b\Q'.str_replace(' ','\E\b)(?=.*\b\Q',$requestedservice).'\E\b)/i'; // with wordboundaries
echo $pattern,"\n";
$result_array=preg_grep($pattern,$allservicesname);
var_export($result_array);
Output:
/(?=.*\Qwalk\E)(?=.*\Qrock\E)/i
array (
0 => 'Walk dance and rock walk',
3 => 'rock and walk',
4 => 'sidewalk and rockwall',
)
If you don't want element [4]
to qualify, then word boundaries are necessary - use the second (commented out) pattern declaration instead.
\Q..\E
ensures that no characters with special meanings in regex can interfere with the execution. The substrings inside of them are interpreted "literally".