2

There's URL parameter :-

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

As you can notice that there are two array-like string. I want to convert them into array
['addr' => ['nation' => ['key' => ['sx' => China]]], ['city' => 'Shanghai']]

I tried:-

    $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);

It works. It gets:

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
    } 
}

But I am afraid of the reference (&) will make mistakes.

Is there a better way to do it?

2
  • 2
    you need to change your link structure through which you are getting this type of url. More easy and correct work. Commented Oct 4, 2016 at 7:47
  • It's just a kinda special needs…… Commented Oct 4, 2016 at 7:49

3 Answers 3

1

Converting it into query string should result in brief code:

$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);
Sign up to request clarification or add additional context in comments.

Comments

0

Some simple regex processing:

$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"

Note that I altered your $replacements data, since it did not correspond to the placeholders in the URL.

Comments

0

Try to use a recursive function

$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);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.