2009-09-13 4 views
2

Я пытаюсь создать многомерный массив, чьи части определяются строкой. Я использую . в качестве разделителя, и каждая часть (за исключением последнего) должен быть массив
например:Как рекурсивно создать многомерный массив?

config.debug.router.strictMode = true 

Я хочу, чтобы одни и те же результаты, как если бы я типа:

$arr = array('config' => array('debug' => array('router' => array('strictMode' => true)))); 

Эта проблема действительно заставила меня ходить в кругах, любая помощь приветствуется. Благодаря!

ответ

4

Давайте предположим, что у нас уже есть ключ и значение в $key и $val, то вы можете сделать это:

$key = 'config.debug.router.strictMode'; 
$val = true; 
$path = explode('.', $key); 

Builing массив слева направо:

$arr = array(); 
$tmp = &$arr; 
foreach ($path as $segment) { 
    $tmp[$segment] = array(); 
    $tmp = &$tmp[$segment]; 
} 
$tmp = $val; 

и справа левый:

$arr = array(); 
$tmp = $val; 
while ($segment = array_pop($path)) { 
    $tmp = array($segment => $tmp); 
} 
$arr = $tmp; 
4

Я говорю, что все разбито, начните с значения, и работайте назад оттуда, каждый раз, обертывая то, что у вас есть внутри другого массива. Например:

$s = 'config.debug.router.strictMode = true'; 
list($parts, $value) = explode(' = ', $s); 

$parts = explode('.', $parts); 
while($parts) { 
    $value = array(array_pop($parts) => $value); 
} 

print_r($parts); 

Обязательно перепишите его, чтобы он проверил ошибки.

+0

Это работает красиво, но мне любопытно, какие ошибки я должен проверять. –

+0

Похоже, что это ломается, если вы хотите разобрать/сохранить несколько строк. – timdev

+0

Руки: он сломается, если в строке нет, например, «=». В принципе, строки, которые не соответствуют синтаксису, в точности заставляют мой скрипт генерировать ошибки php. Вы захотите сделать его намного более прощающим (например, не требуя пробелов рядом с равными) и обрабатывать ошибки каким-либо значимым образом, вместо ошибок php, например «недопустимый аргумент foreach()». – JasonWoof

0
// The attribute to the right of the equals sign 
$rightOfEquals = true; 

$leftOfEquals = "config.debug.router.strictMode"; 

// Array of identifiers 
$identifiers = explode(".", $leftOfEquals); 

// How many 'identifiers' we have 
$numIdentifiers = count($identifiers); 


// Iterate through each identifier backwards 
// We do this backwards because we want the "innermost" array element 
// to be defined first. 
for ($i = ($numIdentifiers - 1); $i >=0; $i--) 
{ 

    // If we are looking at the "last" identifier, then we know what its 
    // value is. It is the thing directly to the right of the equals sign. 
    if ($i == ($numIdentifiers - 1)) 
    { 
     $a = array($identifiers[$i] => $rightOfEquals); 
    } 
    // Otherwise, we recursively append our new attribute to the beginning of the array. 
    else 
    { 
     $a = array($identifiers[$i] => $a); 
    } 

} 

print_r($a); 
1

Ответ Gumbo выглядит хорошо.

Однако, похоже, что вы хотите разобрать типичный файл .ini.

Рассмотрите возможность использования библиотечного кода вместо того, чтобы кататься самостоятельно.

Например, Zend_Config обрабатывает этот вид красиво.

1

Мне очень нравится, что JasonWolf отвечает на это.

Что касается возможных ошибок: да, но он предоставил отличную идею, теперь это до читателя, чтобы сделать его пуленепробиваемым.

Моя потребность была немного более простой: из списка с разделителями создайте массив MD. Я слегка изменил его код, чтобы дать мне именно это. Эта версия предоставит вам массив с или без строки определения или даже строки без разделителя.

Я надеюсь, что кто-то может сделать это еще лучше.

$parts = "config.debug.router.strictMode"; 

$parts = explode(".", $parts); 

$value = null; 

while($parts) { 
    $value = array(array_pop($parts) => $value); 
} 


print_r($value);