使用像'%LIKE%'构造的sql的键值对搜索php多维关联数组

时间:2021-09-30 22:08:13

I have this PHP function that works well at searching a multidimensional associative array using a key value pair. I would now like to extend it to search for an array where the key value pair has an SQL-like construct similar to this: name = '%john%'.

我有这个PHP函数,可以很好地使用键值对搜索多维关联数组。我现在想扩展它以搜索一个数组,其中键值对具有类似于SQL的类似构造:name ='%john%'。

function search($array, $key, $value)
{
    $results = array();
    like_search_r($array, $key, $value, $results);
    return $results[0];
}

function like_search_r($array, $key, $value, &$results)
{
    if (!is_array($array)) {
        return;
    }

    if (isset($array[$key]) && $array[$key] == $value) {
        $results[] = $array;
    }

    foreach ($array as $subarray) {
        like_search_r($subarray, $key, $value, $results);
    }
}

I found a good example here filter values from an array similar to SQL LIKE '%search%' using PHP but it only searches a one-dimensional array. The key in this example is preg_grep but I have not figured how to use it in a multidimensional associative array. Any help is appreciated.

我在这里找到了一个很好的示例,它使用PHP从类似于SQL LIKE'%search%'的数组中过滤值,但它只搜索一维数组。这个例子中的关键是preg_grep,但我还没有想到如何在多维关联数组中使用它。任何帮助表示赞赏。

EDITED: I would love to be able to pass an array of key values pairs to do one sql like filter. The original requirements remain the same. Filter must support something similar to sql '%like%', no input is required, return the root array when a combination of matches are met. If a key/value pair does not match ignore and move on to the next key/value pair. My input array looks like this:

编辑:我希望能够传递一组键值对来做一个像过滤器这样的sql。原始要求保持不变。 Filter必须支持类似于sql'%like%'的东西,不需要输入,当满足匹配组合时返回根数组。如果键/值对与ignore不匹配,则继续执行下一个键/值对。我的输入数组如下所示:

     array('FIRST_NAME'=>'ma','MIDDLE_NAME'=>'bill',
     'LAST_NAME'=>'jo','ALIASES'=>'phil',
     'DOB'=>'2017-07-05','COUNTRY_OF_BIRTH'=>'Jamaica',
     'Countries1'=>array(array('COUNTRY_CODE'=>'JM'),array('COUNTRY_CODE'=>'AL')),
     'Countries2'=>array(array('COUNTRY_CODE'=>'JM'),array('COUNTRY_CODE'=>'AL')));

A sample array to be filtered can be found here: https://www.tehplayground.com/dIMKbb6Tcw5YU38R

可以在此处找到要过滤的示例数组:https://www.tehplayground.com/dIMKbb6Tcw5YU38R

1 个解决方案

#1


2  

I think the way to go is with preg_match():

我认为可行的方法是使用preg_match():

function match($search, $subject)
{
    $search = str_replace('/', '\\/', $search);

    return preg_match("/$search/i", (string)$subject);
}

function like_search_r($array, $key, $value, array &$results = [])
{
    if (!is_array($array)) {
        return;
    }

    $key   = (string)$key;
    $value = (string)$value;

    foreach ($array as $arrayKey => $arrayValue) {
        if (match($key, $arrayKey) && match($value, $arrayValue)) {
            // add array if we have a match
            $results[] = $array;
        }

        if (is_array($arrayValue)) {
            // only do recursion on arrays
            like_search_r($arrayValue, $key, $value, $results);
        }
    }
}

$array1 = [
    'foo'    => 'bar',
    'subarr' => [
        'test'                 => 'val',
        'dangerous/characters' => 1,
    ],
];

$results1 = [];
like_search_r($array1, 'fo', 'bar', $results1);
print_r($results1);

/*
Array
(
    [0] => Array
        (
            [foo] => bar
            [subarr] => Array
                (
                    [test] => val
                    [dangerous/characters] => 1
                )

        )

)
*/

$results2 = [];
like_search_r($array1, 'est', 'val', $results2);
print_r($results2);

/*
Array
(
    [0] => Array
        (
            [test] => val
            [dangerous/characters] => 1
        )

)
*/

$results3 = [];
like_search_r($array1, 's/c', 1, $results3);
print_r($results3);

/*
Array
(
    [0] => Array
        (
            [test] => val
            [dangerous/characters] => 1
        )

)
*/

Adjusted after your comment:

在您的评论后调整:

function match($search, $subject) { /* no change */ }

function like_search_r($array, $key, $value, array &$results = [], $level = 0)
{
    if (!is_array($array)) {
        return false;
    }

    $key   = (string)$key;
    $value = (string)$value;

    $found = false;

    foreach ($array as $arrayKey => $arrayValue) {
        if (match($key, $arrayKey) && match($value, $arrayValue)) {
            return true;
        }

        if (is_array($arrayValue)) {
            // only do recursion on arrays
            // results are only added on top level
            if (like_search_r($arrayValue, $key, $value, $results, $level+1)) {
                if ($level == 1) {
                    $results[] = $array;
                }
                $found = true;
            }
        }
    }

    return $found;
}

$array2   = [['id' => 0, 'values' => ['name' => 'bill']], ['id' => 1, 'values' => ['name' => 'john']]];
$results4 = [];
like_search_r($array2, 'name', 'john', $results4);
print_r($results4);

/*
Array
(
    [0] => Array
        (
            [id] => 1
            [values] => Array
                (
                    [name] => john
                )

        )

)
*/

#1


2  

I think the way to go is with preg_match():

我认为可行的方法是使用preg_match():

function match($search, $subject)
{
    $search = str_replace('/', '\\/', $search);

    return preg_match("/$search/i", (string)$subject);
}

function like_search_r($array, $key, $value, array &$results = [])
{
    if (!is_array($array)) {
        return;
    }

    $key   = (string)$key;
    $value = (string)$value;

    foreach ($array as $arrayKey => $arrayValue) {
        if (match($key, $arrayKey) && match($value, $arrayValue)) {
            // add array if we have a match
            $results[] = $array;
        }

        if (is_array($arrayValue)) {
            // only do recursion on arrays
            like_search_r($arrayValue, $key, $value, $results);
        }
    }
}

$array1 = [
    'foo'    => 'bar',
    'subarr' => [
        'test'                 => 'val',
        'dangerous/characters' => 1,
    ],
];

$results1 = [];
like_search_r($array1, 'fo', 'bar', $results1);
print_r($results1);

/*
Array
(
    [0] => Array
        (
            [foo] => bar
            [subarr] => Array
                (
                    [test] => val
                    [dangerous/characters] => 1
                )

        )

)
*/

$results2 = [];
like_search_r($array1, 'est', 'val', $results2);
print_r($results2);

/*
Array
(
    [0] => Array
        (
            [test] => val
            [dangerous/characters] => 1
        )

)
*/

$results3 = [];
like_search_r($array1, 's/c', 1, $results3);
print_r($results3);

/*
Array
(
    [0] => Array
        (
            [test] => val
            [dangerous/characters] => 1
        )

)
*/

Adjusted after your comment:

在您的评论后调整:

function match($search, $subject) { /* no change */ }

function like_search_r($array, $key, $value, array &$results = [], $level = 0)
{
    if (!is_array($array)) {
        return false;
    }

    $key   = (string)$key;
    $value = (string)$value;

    $found = false;

    foreach ($array as $arrayKey => $arrayValue) {
        if (match($key, $arrayKey) && match($value, $arrayValue)) {
            return true;
        }

        if (is_array($arrayValue)) {
            // only do recursion on arrays
            // results are only added on top level
            if (like_search_r($arrayValue, $key, $value, $results, $level+1)) {
                if ($level == 1) {
                    $results[] = $array;
                }
                $found = true;
            }
        }
    }

    return $found;
}

$array2   = [['id' => 0, 'values' => ['name' => 'bill']], ['id' => 1, 'values' => ['name' => 'john']]];
$results4 = [];
like_search_r($array2, 'name', 'john', $results4);
print_r($results4);

/*
Array
(
    [0] => Array
        (
            [id] => 1
            [values] => Array
                (
                    [name] => john
                )

        )

)
*/