phparraysmultidimensional-arraycase-insensitivearray-filter

Filter a 2d array to keep rows with a value in any column which case-insensitively matches a search substring


I have a script which allows me to filter an entire multidimensional array according to a string. But it will only work if a value of the array matches the string exactly while I would like it to work when the string is at least contained in the value.

So, in other words, if the string is "nana", I would like the filtering to let the values "Banana" and "Ananas" be a match. So I would like the search to be done on "%nana%" in order to allow any combination of letters before and after the "nana" string.

Here is my code so far:

$dataset = [
    [3, "Yellow", "Banana"],
    [2, "Brown", "Ananas"],
    [1, "Green", "brown"]
];

$dataset = array_filter($dataset, function ($v){
    return filterArray('anana', $v);
});

function filterArray($needle,$haystack){
    $needle = strtolower($needle);

    foreach($haystack as $k => $v){
        $haystack[$k] = strtolower($v);
    };
   
    return in_array($needle,$haystack);
}

echo '<pre>'; print_r($dataset); echo '</pre>';

This won't work.

I made my homework and found that "fnmatch" or "preg_match" are referenced rather often for this case. The problem is I don't see where they should be in my script. The cases I've browsed are different enough for me not to know how to use them properly here. So it's not about looking the proper function per se but rather about understanding how and where to use it.

I tried this but it didn't work:

....
foreach($haystack as $k => $v){
    if(preg_match('/^'.$needle.'$/i', $v)) {    
        $haystack[$k] = strtolower($v);
    } 
};
....

And this didn't work neither:

....
foreach($haystack as $k => $v){
    if(preg_match("/\b$needle\b/i", $v)) {
        $haystack[$k] = strtolower($v); 
    } 
};
....

I also tried this :

....
$dataset = array_filter(dataset, function ($v){
    return filter((bool)preg_match("/$needle/i",$v);
});
....

None of those changes did any good and it feels to me like I exhausted the solutions found online and in here about this.

I also tried to use "fnmatch", even if I wasn't sure how and where to use it, but with no success.


Solution

  • You can use stripos to do a case-insensitive search for the $needle anywhere inside the $haystack value:

    $dataset=[[3,"Yellow","Banana"], [2,"Brown","Ananas"], [1,"Green","brown"]];
    
    $dataset = array_filter($dataset, function ($v){
        return filterArray('anana', $v);
    });
    
    function filterArray($needle,$haystack){
        foreach($haystack as $v){
            if (stripos($v, $needle) !== false) return true;
        };
        return false;
    }
    
    echo '<pre>'; print_r($dataset); echo '</pre>';
    

    Output:

    <pre>Array
    (
        [0] => Array
            (
                [0] => 3
                [1] => Yellow
                [2] => Banana
            )
        [1] => Array
            (
                [0] => 2
                [1] => Brown
                [2] => Ananas
            )
    )
    </pre>
    

    Demo on 3v4l.org