3

I have this example php string:

$string = "@[item_1][door] @[mozart][grass] = yes @[mozart][green] = no @[mozart][human] @[blue][movie]=yes @[item_1][beat] = yes @[item_1][music] = no ";

now $string idented just to easy view:

  1. @[item_1][door]
    • @[mozart][grass] = yes
    • @[mozart][green] = no
    • @[mozart][human]

      • @[blue][movie]=yes

    • @[item_1][beat] = yes
    • @[item_1][music] = no

I want to know how can i get this string ( or other string following this style ) and transform in an array that looks like:

Array
(
    [item_1] => Array
        (
            [door] => Array
                (
                    [mozart] => Array
                        (
                            [grass] => yes
                            [green] => no
                            [human] => Array
                                (
                                    [blue] => Array
                                        (
                                            [movie] => yes
                                        )
                                )
                        )
                )
            [beat] => yes
            [music] => no
        )
)

What i tried

I tried to use and recursive function to create an nested array but i can't have access to the array pointer ( in deep levels ) in recursive functions.. don't know why.. maybe is the wrong patch to the answer. thank you,

6
  • You could show your recursive function. If you worked with a reference, it might be necessary to keep a list of them, as you are moving in and out of subarrays with this approach. Commented Dec 30, 2011 at 5:34
  • How does one logically determine that blue is an array inside of Human from the original string? If you can't define a reasonably simple rule to determine this, it will be hard or impossible to code. Commented Dec 30, 2011 at 20:11
  • Why not stick to XML or JSON? Commented Dec 31, 2011 at 11:33
  • The format isn't clear in your string. For example, line 1 is outdented, and yet line 6 (@[item_1][beat] = yes) is indented to 1 level in. There is no clear format here. Commented Jan 2, 2012 at 14:22
  • The string has a format, i have already a function that handle it now - gist.github.com/1553533 - the problem now is i'm trying to convert it to JSON with some detail i will explain on the topic. @mario Commented Jan 3, 2012 at 4:48

1 Answer 1

3

OK, I hope you still need this, because I wasted more time than I'd like to admin getting this right :)

Basically, my approach was to first manipulate the string into the format [set][of][keys]=value, and then loop through the string of keys and comparing them with the last set of keys to create the correct key hierarchy. I used eval because it's easier, but you can write a replacement function if you can't stomach seeing that function in your code:

//FIRST WE GET THE STRING INTO EASIER TO WORK WITH CHUNKS
$original_string = "@[item_1][door] @[mozart][grass] = yes @[mozart][green] = no @[mozart][human] @[blue][movie]=yes @[item_1][beat] = yes @[item_1][music] = no ";
$cleaned_string = str_replace('] @[','][',$original_string);
/* This results in clusters of keys that equal a value:
@[item_1][door][mozart][grass] = yes @[mozart][green] = no @[mozart][human][blue][movie]=yes @[item_1][beat] = yes @[item_1][music] = no 

OR (with line breaks for clarity):

@[item_1][door][mozart][grass] = yes 
@[mozart][green] = no 
@[mozart][human][blue][movie]=yes 
@[item_1][beat] = yes 
@[item_1][music] = no */

//break it up into an array:
$elements = explode('@',$cleaned_string);

//create a variable to compare the last string to
$last_keys = "";
//and another that will serve as our final array
$array_of_arrays = array();
//now loop through each [item_1][door][mozart][grass] = yes,[mozart][green] = no, etc
foreach($elements as $element){
    if ($element==""){continue;} //skip the first empty item

    //break the string into [0] = group of keys and [1] the value that terminates the string 
    //so [item_1][door][mozart][grass] = yes BECOMES [item_1][door][mozart][grass], AND yes
    $pieces = explode('=',str_replace(array('[',']'),array("['","']"),trim($element))); 
    //now compare this set of keys to the last set of keys, and if they overlap merge them into a single key string
    $clean_keys = combine_key_strings($pieces[0],$last_keys);
    //set the new key string the value for the next comparison
    $last_keys = $clean_keys;
    //and (ugly, I know) we use an eval to convert "[item_1][door][mozart][grass]='yes'" into a properly keyed array
    eval("\$array_of_arrays".$clean_keys." = '".trim($pieces[1])."';");
}

//now dump the contents
print_r($array_of_arrays);


//THIS FUNCTION COMPA
function combine_key_strings($new,$old){
    //get the key that starts the newer string
    $new_keys = explode('][',$new);
    $first_key = $new_keys[0].']';

    //see if it appears in the last string
    $last_occurance = strrpos ($old,$first_key);
    //if so, merge the two strings to create the full array keystring
    if (is_int($last_occurance)){
        return substr($old,0,$last_occurance).$new;
    }
    return $new;
}

This should spit out your correctly nested array:

Array
(
    [item_1] => Array
        (
            [door] => Array
                (
                    [mozart] => Array
                        (
                            [grass] => yes
                            [green] => no
                            [human] => Array
                                (
                                    [blue] => Array
                                        (
                                            [movie] => yes
                                        )

                                )

                        )

                )

            [beat] => yes
            [music] => no
        )

)

Good night!

Sign up to request clarification or add additional context in comments.

2 Comments

That's great! thank you so much @ben-d ! this was a really big problem! great function! thank you !
Just keep in mind my warning about the eval() call... if there is any chance that data could replicate a php function call (especially if any of the data is being set by third parties) you could face php injection risks, in which case you'll want to write a custom function to handle this process (generate an array and recursively merge it with the master array). Good luck!

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.