Reputation: 3
i hope someone can help.
I have a string as following
$string = 'latitude=46.6781471,longitude=13.9709534,options=[units=auto,lang=de,exclude=[hourly,minutely]]';
Now what i am trying is to create an array out of each key, value pair but badly failing with regex for preg_match_all()
Currently my attempts aren't giving desired results, creating key => value pairs works as long as there are no brackets, but i have absolutely no idea how to achieve a multidimensional array if key contains key/value pairs inside brackets in example.
Array (
[0] => Array
(
[0] => latitude=46.6781471,
[1] => longitude=13.9709534,
[2] => options=[units=si,
[3] => lang=de,
)
[1] => Array
(
[0] => latitude
[1] => longitude
[2] => options=[units
[3] => lang
)
.. and so on
Where in the end i would like to achieve results as following.
Array (
[latitude] => 46.6781471
[longitude] => 13.9709534
[options] => Array
(
[units] => auto
[exclude] => hourly,minutely
)
)
I would appreciate any help or example how i can achieve this from a given string.
Upvotes: 0
Views: 623
Reputation: 892
If you don't want parser you can also try this code. It converts your string to JSON and decode to array. But as others said, I think you should try the approach with JSON. If you're sending this string by XmlHttpRequest in JavaScript it will not be hard to create proper JSON code to send.
$string = 'latitude=46.6781471,longitude=13.9709534,options=[units=auto,lang=de,exclude=[hourly,minutely]]';
$string = preg_replace('/([^=,\[\]\s]+)/', '"$1"', $string);
$string = '{' . $string . '}';
$string = str_replace('=', ':', $string);
$string = str_replace('[', '{', $string);
$string = str_replace(']', '}', $string);
$string = preg_replace('/({[^:}]*})/', '|$1|', $string);
$string = str_replace('|{', '[', $string);
$string = str_replace('}|', ']', $string);
$result = json_decode($string, true);
print_r($result);
Upvotes: 0
Reputation: 1529
Regular expression isn't the right tool to deal with recursive matches. You can write a parser instead of a regex (or use JSON, query string, XML or any other commonly used format):
function parseOptionsString($string) {
$length = strlen($string);
$key = null;
$contextStack = array();
$options = array();
$specialTokens = array('[', ']', '=', ',');
$buffer = '';
$currentOptions = $options;
for ($i = 0; $i < $length; $i++) {
$currentChar = $string[$i];
if (!in_array($currentChar, $specialTokens)) {
$buffer .= $currentChar;
continue;
}
if ($currentChar == '[') {
array_push($contextStack, [$key, $currentOptions]);
$currentOptions[$key] = array();
$currentOptions = $currentOptions[$key];
$key = '';
$buffer = '';
continue;
}
if ($currentChar == ']') {
if (!empty($buffer)) {
if (!empty($key)) {
$currentOptions[$key] = $buffer;
} else {
$currentOptions[] = $buffer;
}
}
$contextInfo = array_pop($contextStack);
$previousContext = $contextInfo[1];
$thisKey = $contextInfo[0];
$previousContext[$thisKey] = $currentOptions;
$currentOptions = $previousContext;
$buffer = '';
$key = '';
continue;
}
if ($currentChar == '=') {
$key = $buffer;
$buffer = '';
continue;
}
if ($currentChar == ',') {
if (!empty($key)) {
$currentOptions[$key] = $buffer;
} else if (!empty($buffer)) {
$currentOptions[] = $buffer;
}
$buffer = '';
$key = '';
continue;
}
}
if (!empty($key)) {
$currentOptions[$key] = $buffer;
}
return $currentOptions;
}
this gives the following output:
print_r(parseOptionsString($string));
Array
(
[latitude] => 46.6781471
[longitude] => 13.9709534
[options] => Array
(
[units] => auto
[lang] => de
[exclude] => Array
(
[0] => hourly
[1] => minutely
)
)
)
Note also that you want a special syntax for arrays with only comma separated values (exclude=[hourly,minutely] becomes exclude => hourly,minutely and not exclude => array(hourly, minutely)). I think this is an inconsistency in your format and I wrote the parser with the "correct" version in mind.
Upvotes: 2