Reputation: 1476
I have a string
Label 1|80|default
Label 2|100|default
---
Frontend|80|red
Backend|20|red
---
Another Item 1|20|blue
Another Item 2|20|blue
-
And another Item|20|blue
which should be converted to the following array
Array
(
[0] => Array
(
[items] => Array
(
[0] => Array
(
[label] => Label 1
[value] => 80
[color] => default
)
[1] => Array
(
[label] => Label 2
[value] => 100
[color] => default
)
)
)
[1] => Array
(
[items] => Array
(
[0] => Array
(
[label] => Frontend
[value] => 80
[color] => red
)
[1] => Array
(
[label] => Backend
[value] => 20
[color] => red
)
)
)
[2] => Array
(
[items] => Array
(
[0] => Array
(
[label] => And another Item
[value] => 20
[color] => blue
)
)
)
)
to be converted into json:
[{"items":[{"label":"Label 1","value":"80","color":"default"},{"label":"Label 2","value":"100","color":"default"}]},{"items":[{"label":"Frontend","value":"80","color":"red"},{"label":"Backend","value":"20","color":"red"}]},{"items":[{"label":"And another Item","value":"20","color":"blue"}]}]
Currently, my way of doing that string splitting to multiple arrays seems a bit complicated to me. At least, it is hard to read.
protected function convertPartsToObject($parts): array
{
$return = [];
$arr1 = explode("---", trim($parts));
foreach ($arr1 as $arr1Item) {
$arr2 = explode("-", trim($arr1Item));
foreach ($arr2 as $arr2Item) {
$arr3 = explode("\n", trim($arr2Item));
$group = [];
foreach ($arr3 as $arr3Item) {
$arr4 = explode("|", trim($arr3Item));
$item = [
'label' => $arr4[0],
'value' => $arr4[1],
'color' => $arr4[2]
];
$group['items'][] = $item;
}
}
$return[] = $group;
}
return $return;
}
Question:
Is there a better / more readable way to convert strings by multiple delimiters to an associative array? Maybe with a nested regex?
Background, just as an info: This is part of a content management system, where I need some data as json in frontend (for react). And I don't want the editors to learn the json syntax...
Upvotes: 0
Views: 102
Reputation: 47894
Rather than maintaining temporary arrays to be pushed into a parent array when they are "completed" and after the loop is finished, this is an excellent case for implementing a reference variable. Think of the reference variable as a magical soccer goal -- once declared, you can close your eyes, kick your soccer ball and no matter where the ball travels, it will swish into the back of the net as desired. When you want to have a new soccer goal, just destroy the old one (unset()
) and create a new one with the same technique.
This technique reduces the code length and is easily read by humans -- so long as you understand how reference variables work.
I should include a caveat, that if your input array is empty, you'll probably want an early return in your method so that the reference variable never pushes any entries into your result array.
Code: (Demo)
function stringToGroupedArray(string $string): array
{
$result = [];
$result[]['items'] = &$items;
foreach (explode(PHP_EOL, $string) as $line) {
if ($line[0] === '-') { // or however you want to identify the separator
unset($items);
$result[]['items'] = &$items;
} else {
$items[] = array_combine(['label', 'value', 'color'], explode('|', $line, 3));
}
}
return $result;
}
Upvotes: 0
Reputation: 57121
This is an alternative to your current code. Instead of the nested explode()
it just splits the input into lines and then processes the lines. For ---
it just adds the current data into the result, -
removes the current stored data(not sure if it should), else it extracts the data (I've used the ability to explode to an associative array as a shorthand, depends if you like it or not you can use your current method)...
function convertPartsToObject ( $parts ) : array {
$return = [];
$buffer = [];
foreach ( explode( PHP_EOL, $parts ) as $line ) {
if ( trim($line) == "---" ) {
$return[]['items'] = $buffer;
$buffer = [];
}
elseif ( trim($line) == "-" ) {
$buffer = [];
}
else {
[$arr4['label'], $arr4['value'], $arr4['color']] = explode("|", trim($line));
$buffer[] = $arr4;
}
}
// Add last items
$return[]['items'] = $buffer;
return $return;
}
Upvotes: 1