Reputation: 164
I'm in PHP and I've got an array that looks like this. A single dimension array whose keys are bracketed strings.
array(
'matrix[min_rows]' => '0',
'matrix[max_rows]' => '',
'matrix[col_order][]' => 'col_new_1',
'matrix[cols][col_new_0][type]' => 'text',
'matrix[cols][col_new_1][type]' => 'text',
'matrix[cols][col_new_0][label]' => 'Cell 1',
'matrix[cols][col_new_1][label]' => 'Cell 2',
'matrix[cols][col_new_0][name]' => 'cell_1',
'matrix[cols][col_new_1][name]' => 'cell_2',
'matrix[cols][col_new_0][instructions]' => '',
'matrix[cols][col_new_1][instructions]' => '',
'matrix[cols][col_new_0][width]' => '33%',
'matrix[cols][col_new_1][width]' => '',
'matrix[cols][col_new_0][settings][maxl]' => '',
'matrix[cols][col_new_0][settings][fmt]' => 'none',
'matrix[cols][col_new_0][settings][content]' => 'all',
'matrix[cols][col_new_1][settings][maxl]' => '140',
'matrix[cols][col_new_1][settings][multiline]' => 'y',
'matrix[cols][col_new_1][settings][fmt]' => 'none',
'matrix[cols][col_new_1][settings][content]' => 'all',
)
Is there any easy way to convert that to a normal nested array, ie:
array(
'matrix' => array(
'min_rows' => '0',
'max_rows' => '',
'col_order' => array('col_new_1'),
'cols' => array(
'col_new_0' => array(
'type' => 'text',
'label' => 'Cell 1',
....etc....
This is my current solution, but I was wondering if there's something more native or efficient:
foreach ($decoded_field_type_settings as $key => $value)
{
if (preg_match_all('/\[(.*?)\]/', $key, $matches))
{
$new_key = substr($key, 0, strpos($key, '['));
if ( ! isset($field_type_settings[$new_key]))
{
$field_type_settings[$new_key] = array();
}
$array =& $field_type_settings[$new_key];
$count = count($matches[1]) - 1;
foreach ($matches[1] as $i => $sub_key)
{
if ( ! $sub_key)
{
if ($i < $count)
{
$array[] = array();
}
else
{
$array[] = $value;
}
}
else
{
if ( ! isset($array[$sub_key]))
{
if ($i < $count)
{
$array[$sub_key] = array();
}
else
{
$array[$sub_key] = $value;
}
}
}
if ($i < $count)
{
$array =& $array[$sub_key];
}
}
}
else
{
$field_type_settings[$key] = $value;
}
}
UPDATE: I posted an answer below.
Upvotes: 1
Views: 235
Reputation: 164
This was the simplest solution, involving no regex parsing:
$original_array = array(
'matrix[min_rows]' => '0',
'matrix[max_rows]' => '',
'matrix[col_order][]' => 'col_new_1',
'matrix[cols][col_new_0][type]' => 'text',
'matrix[cols][col_new_1][type]' => 'text',
'matrix[cols][col_new_0][label]' => 'Cell 1',
'matrix[cols][col_new_1][label]' => 'Cell 2',
'matrix[cols][col_new_0][name]' => 'cell_1',
'matrix[cols][col_new_1][name]' => 'cell_2',
'matrix[cols][col_new_0][instructions]' => '',
'matrix[cols][col_new_1][instructions]' => '',
'matrix[cols][col_new_0][width]' => '33%',
'matrix[cols][col_new_1][width]' => '',
'matrix[cols][col_new_0][settings][maxl]' => '',
'matrix[cols][col_new_0][settings][fmt]' => 'none',
'matrix[cols][col_new_0][settings][content]' => 'all',
'matrix[cols][col_new_1][settings][maxl]' => '140',
'matrix[cols][col_new_1][settings][multiline]' => 'y',
'matrix[cols][col_new_1][settings][fmt]' => 'none',
'matrix[cols][col_new_1][settings][content]' => 'all',
);
$query_string = http_build_query($original_array);
$final_array = array();
parse_str($query_string, $final_array);
var_dump($final_array);
Upvotes: 0
Reputation: 197777
You can make use of a simple, regular expression based parser that creates a multidimensional array based on the information stored in the string per each key:
function parse_flat_matrix(array $flat)
{
$matrix = array();
$varname = 'matrix';
$nameToken = '[a-z0-9_]*';
foreach($flat as $key => $value)
{
$keys = preg_split(sprintf('/(\[%s\])/', $nameToken), $key, 0, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
if ($varname !== array_shift($keys))
{
throw new InvalidArgumentException(sprintf('Invalid key %s.', $key));
}
$p =& $matrix;
foreach($keys as $k)
{
$r = preg_match(sprintf('/^\[(%s)\]$/', $nameToken), $k, $kk);
if (!$r)
{
throw new InvalidArgumentException(sprintf('Invalid subkey %s in key %s.', $k, $key));
}
if ('' === $kk[1])
{
$p =& $p[];
}
else
{
$p =& $p[$kk[1]];
}
}
$p = $value;
unset($p);
}
return $matrix;
}
With your example data given, it will create this array:
Array
(
[min_rows] => 0
[max_rows] =>
[col_order] => Array
(
[0] => col_new_1
)
[cols] => Array
(
[col_new_0] => Array
(
[type] => text
[label] => Cell 1
[name] => cell_1
[instructions] =>
[width] => 33%
[settings] => Array
(
[maxl] =>
[fmt] => none
[content] => all
)
)
[col_new_1] => Array
(
[type] => text
[label] => Cell 2
[name] => cell_2
[instructions] =>
[width] =>
[settings] => Array
(
[maxl] => 140
[multiline] => y
[fmt] => none
[content] => all
)
)
)
)
Upvotes: 0
Reputation: 23041
It seems that the OP wants, as output, an array declaration which can be parsed directly by PHP. So I suggest to use var_export()
.
$array = array(
'matrix[min_rows]' => '0',
// ......
// ......
// ......
'matrix[cols][col_new_1][settings][content]' => 'all'
);
$matrix = array();
foreach ($array as $key => $value)
{
// fix missing quotes around array indexes
$key = str_replace(array("[", "]", "['']"), array("['", "']", "[]"), $key);
// fill PHP array
eval('$'.$key.' = $value;');
}
var_export($matrix);
Upvotes: 0
Reputation: 21466
I think this should do it...
<?php
function convert2dTo3d($source) {
$refs = array();
$output = array();
foreach ($source AS $key => $val) {
$tok = strtok($key, '[]');
$prev_tok = NULL;
while ($tok !== FALSE) {
$this_ref =& $refs[$tok];
if ($prev_tok === NULL)
$output[$tok] =& $this_ref;
else
$refs[$prev_tok][$tok] =& $this_ref;
$prev_tok = $tok;
$tok = strtok('[]');
if ($tok === FALSE)
$refs[$prev_tok] = $val;
}
}
return $output;
}
// Test
$source = array(
'matrix[min_rows]' => '0',
'matrix[max_rows]' => '',
'matrix[col_order][]' => 'col_new_1',
'matrix[cols][col_new_0][type]' => 'text',
'matrix[cols][col_new_1][type]' => 'text',
'matrix[cols][col_new_0][label]' => 'Cell 1',
'matrix[cols][col_new_1][label]' => 'Cell 2',
'matrix[cols][col_new_0][name]' => 'cell_1',
'matrix[cols][col_new_1][name]' => 'cell_2',
'matrix[cols][col_new_0][instructions]' => '',
'matrix[cols][col_new_1][instructions]' => '',
'matrix[cols][col_new_0][width]' => '33%',
'matrix[cols][col_new_1][width]' => '',
'matrix[cols][col_new_0][settings][maxl]' => '',
'matrix[cols][col_new_0][settings][fmt]' => 'none',
'matrix[cols][col_new_0][settings][content]' => 'all',
'matrix[cols][col_new_1][settings][maxl]' => '140',
'matrix[cols][col_new_1][settings][multiline]' => 'y',
'matrix[cols][col_new_1][settings][fmt]' => 'none',
'matrix[cols][col_new_1][settings][content]' => 'all',
);
echo "<pre>";
print_r(convert2dTo3d($source));
echo "</pre>";
Upvotes: 0
Reputation: 60498
This might work, although it would probably generate some warnings:
$matrix = array();
foreach($arr as $key => $value) {
eval('$' . $key . ' = \'' . $value . '\';');
}
var_dump($matrix);
Upvotes: 1