使用键值对和类SQL的'%LIKE%'结构在PHP多维关联数组中搜索。

4

我有一个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);
    }
}

我在这里找到了一个很好的例子(使用PHP从类似于SQL LIKE'%search%'的数组中过滤值),但它只能搜索一维数组。这个例子中的关键是preg_grep,但我还没有弄清楚如何在多维关联数组中使用它。任何帮助都将不胜感激。
编辑后:我希望能够传递一个键值对的数组来进行类似sql的筛选,原始要求仍然相同。过滤器必须支持类似于sql的'%like%',不需要输入,当匹配组合满足时返回根数组。如果键/值对不匹配,则忽略并继续下一个键/值对。我的输入数组如下:
     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')));

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

1个回答

3

我认为使用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
                )

        )

)
*/

它确实可以工作,但唯一的问题是它区分大小写。因此,如果存储的值为“Mark”,而我搜索“ma”,我将不会得到结果。然而,如果我搜索“Ma”,我就能得到结果。另外,第三个测试对我来说没有起作用,但它并不是一个重要的用例。让它不区分大小写,我就会给你50分。 - jessiPP
我已经修改了它,使其不区分大小写。在匹配模式后只需加上一个“i”即可。 - colburton
我试图给你奖励,但它说我必须等待13个小时。 - jessiPP
传递一个名称-值对数组并基于这些值的组合进行过滤,这有多难? - jessiPP
我仍然不明白为什么你不能简单地使用 foreach ($inputArray ...) like_search_r(...) - colburton
显示剩余8条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接