从URL中解析嵌套数组

时间:2016-10-04 07:40:58

标签: php arrays

网址参数: -

/name/Aario/gender/male/addr[nation][key][sx]/China/addr[city]/Shanghai

你可以注意到有两个类似数组的字符串。我想将它们转换为数组['addr' => ['nation' => ['key' => ['sx' => China]]], ['city' => 'Shanghai']]

我试过了: -

    $results = [];
$str = '/name/Aario/gender/male/addr[nation][key][sx]/China/addr[city]/Shanghai/';
$params = explode('/', $str);
if($params[0] == '') unset($params[0]);
while(key($params) !== null && current($params)) {
    $key = current($params);
    $value = next($params);
    if(strpos($key, '[')) {
        $sub_keys = explode('[', $key);
        foreach($sub_keys as &$sub_key) {
            $sub_key = trim($sub_key, ']');
        }

        $count = count($sub_keys);
        $ref = &$results;
        foreach($sub_keys as $k => $v) {
            if($k == $count - 1) {
                $ref[$v] = $value;
                $ref = &$ref[$v];
            } else {
                $ref[$v] = $ref[$v] ?? [];
                $ref = &$ref[$v];
            }
        }
    } else {
        $results[$key] = $value;
    }
    next($params);
}
var_dump($results);

有效。得到:

array(3) { 
    ["name"]=> string(5) "Aario" 
    ["gender"]=> string(4) "male" 
    ["addr"]=> array(2) { 
        ["nation"]=> array(1) { 
            ["key"]=> array(1) { 
                ["sx"]=> string(5) "China" 
            } 
        } 
        ["city"]=> &string(8) "Shanghai"      // please notice here
    } 
}

但我担心引​​用(&)会犯错误。

有更好的方法吗?

3 个答案:

答案 0 :(得分:1)

将其转换为查询字符串应该会产生简短的代码:

$str = '/name/Aario/gender/male/addr[nation][key][sx]/China/addr[city]/Shanghai/';
$query = array_reduce(
    array_chunk(explode('/', trim($str, '/')), 2),
    function ($string, $item) {
        return $string . $item[0] . (isset($item[1]) ? '=' . $item[1] : '') . '&';
    }
);

parse_str($query, $result);

答案 1 :(得分:0)

一些简单的正则表达式处理:

context.callbackWaitsForEmptyEventLoop = true;

allPromises = getDatafromDynamo();
allPromises.then(results => {
  console.log('Results are', JSON.stringify(results));
  context.callbackWaitsForEmptyEventLoop = false;
  callback(null, 'DONE');
  return;
}).catch((err) => {
  console.log("Error occurred", err);
  context.callbackWaitsForEmptyEventLoop = false;
  callback(err);
});  
$replacements = [
    'addr' => [
        'nation' => [
            'key' => [
                'sx' => 'China'
            ]
        ],
        'city' => 'Shanghai'
    ]
];

$url = '/name/Aario/gender/male/addr[nation][key][sx]/China/addr[city]/Shanghai';

$result = preg_replace_callback('~[^/]+~', function (array $match) use ($replacements) {
    if (preg_match_all('/\w+/', $match[0], $keys) > 1) {
        return array_reduce($keys[0], function ($a, $k) { return $a[$k]; }, $replacements);
    } else {
        return $match[0];
    }
}, $url);

var_dump($result);

请注意,我更改了您的string(53) "/name/Aario/gender/male/China/China/Shanghai/Shanghai" 数据,因为它与网址中的占位符不对应。

答案 2 :(得分:0)

尝试使用递归函数

$str = '/name/Aario/gender/male/addr[nation][key][sx]/China/addr[city]/Shanghai/';
$params = explode('/', $str);
if($params[0] == '') unset($params[0]);


$is_odd_pos = true;
$results = [];

function rec(&$array, $keys, $val){
    $keys = array_values($keys);

    if(count($keys) > 1){
        $key = $keys[0];
        if(!isset($array[$key]))
            $array[$key] = [];

        rec($array[$key], array_slice($keys, 1), $val);
        return;
    }

    $array[$keys[0]] = $val;
}

foreach($params as $k => $value) {
    if($k % 2 == 0){
        $key = $params[$k - 1];
        preg_match_all('/\[(\w+)\]/', $key, $matches);
        if(count($matches[1]) == 0){
            $results[$key] = $value;
            continue;
        }
        $key = explode('[', $key, 2)[0];
        if(!isset($results[$key]))
            $results[$key] = [];

        rec($results[$key], $matches[1], $value);
    }
}

var_dump($results);