Convert indented text to multi dimensional array in php. I have tried some examples for indenting
text to PHP multi dimensional array but to no avail. Here is what I did so far. The first text in string has no indent and after that 3 space indents and so on.
<?php
function convertIndentedTextToArray($text) {
$lines = explode("n", $text);
$result = [];
$stack = [];
foreach ($lines as $line) {
$indent = 0;
while (substr($line, 0, 1) === " ") {
$indent++;
$line = substr($line, 1);
}
$node = ['value' => trim($line), 'children' => []];
while ($indent < count($stack)) {
array_pop($stack);
}
if (empty($stack)) {
$result[] = &$node;
} else {
$parent = &$stack[count($stack) - 1];
$parent['children'][] = &$node;
}
$stack[] = &$node;
}
return $result;
}
I also tried this example
$string = <<<EOT
Hey again I am on root
Hey it's wonderful
This is good time
I love the way you are
Hey again I am on root
EOT;
$lines = explode("n", $string);
$output = [];
$currentNode = &$output;
$indent1 = 1;
$elementIndex = 0; // Initialize index for ManagedElements
$hold = [];
$cnt=0;$cnt2=0;
$incre=1;
$first=0;
foreach ($lines as $line) {
$trimmedLine = trim($line);
$indentationLevel = strlen($line) - strlen($trimmedLine);
if ($indentationLevel == 0) {
$elementIndex++; // Increment index for each new ManagedElement
$hold[$elementIndex]['parent'][] = trim($line);
} else if ($indentationLevel == 3) {
$hold[$elementIndex]['parent']['child'][] = trim($line);
$cnt=count($hold[$elementIndex]['parent']['child'])-$incre;
} else if ($indentationLevel == 6) {
$hold[$elementIndex]['parent']['child']['child'][$cnt][] = trim($line);
$cnt2=count($hold[$elementIndex]['parent']['child']['child'])-$incre;
}
else if ($indentationLevel == 9) {
$hold[$elementIndex]['parent']['child']['child']['child'][$cnt2][] = trim($line);
}
}
echo "<pre>";
print_r($hold);
echo "</pre>";
Input:
$input = "Hello world I am good
Hey it's wonderful
This is good time
I love the way you are
Hey again I am on root";
But I am getting output with children array blank:
array (
0 =>
array (
'value' => 'Hey again I am on root',
'children' =>
array (
),
),
1 =>
array (
'value' => 'Hey again I am on root',
'children' =>
array (
),
),
)
This is the expected output:
array (
0 =>
array (
'value' => 'Hey again I am on root',
'children' =>
array (
'value'=>'Hey it's wonderful',
'children'=>array()
),
array (
'value'=>'This is good time',
'children'=>array('value'=>'I love the way you are','children'=>array())
),
),
1 =>
array (
'value' => 'Hey again I am on root',
'children' =>
array (
),
),
)
3
Answers
Your code was over-cluttered, but basically your string wasn’t presented in the same format that the code requires, i.e. a multiple of 3 leading spaces and no trailing spaces.
(https://www.tehplayground.com/zmiKIdTfNqXapTaP)
produces
Ok, I have made this dynamic with respect to spaces.
The way I have done it is to
Not use stack like structure since the copy by value and copy by reference can create clumsy code and would be quite unreadable with respect to what sits in the stack and what goes into the final result.
calculate the no. of leading spaces in the string.
Go to the deeply nested kid or child array till leading spaces’ times and find the correct child to add the current text or line to.
While traversing, always find the last kid of the current array since that is where the current one is going to be added to.
Snippet:
Live Demo
Make sure to trim ending spaces before comparing
strlen($line) - strlen($trimmedLine)
, asstrlen('Hey I am on root ') != strlen(trim('Hey I am on root '))
I have also added a new key in your structure to simplify the logic.
Live Demo