I am trying to parse a time expression string into an associative array with full-word keys.
My input:
$time = "1d2h3m";
My desired output:
array(
"day" => 1,
"hour" => 2,
"minutes" => 3
)
I have tried to extract the numbers with explode()
.
$time = "1d2h3m";
$day = explode("d", $time);
var_dump($day); // 0 => string '1' (length=1)
// 1 => string '2h3m' (length=4)
How can I convert my strictly formatted string into the desired associative array?
This approach uses a regular expression to extract the values and an array to map the letters to the words.
<?php
// Initialize target array as empty
$values = [];
// Use $units to map the letters to the words
$units = ['d'=>'days','h'=>'hours','m'=>'minutes'];
// Test value
$time = '1d2h3m';
// Extract out all the digits and letters
$data = preg_match_all('/(\d+)([dhm])/',$time,$matches);
// The second (index 1) array has the values (digits)
$unitValues = $matches[1];
// The third (index 2) array has the keys (letters)
$unitKeys = $matches[2];
// Loop through all the values and use the key as an index into the keys
foreach ($unitValues as $k => $v) {
$values[$units[$unitKeys[$k]]] = $v;
}
Customizable function, and the most important thing, that you can catch an exception if input is not properly formed
/**
* @param $inputs string : date time on this format 1d2h3m
* @return array on this format "day" => 1,
* "hour" => 2,
* "minutes" => 3
* @throws Exception
*
*/
function dateTimeConverter($inputs) {
// here you can customize how the function interprets input data and how it should return the result
// example : you can add "y" => "year"
// "s" => "seconds"
// "u" => "microsecond"
// key, can be also a string
// example "us" => "microsecond"
$dateTimeIndex = array("d" => "day",
"h" => "hour",
"m" => "minutes");
$pattern = "#(([0-9]+)([a-z]+))#";
$r = preg_match_all($pattern, $inputs, $matches);
if ($r === FALSE) {
throw new Exception("can not parse input data");
}
if (count($matches) != 4) {
throw new Exception("something wrong with input data");
}
$datei = $matches[2]; // contains number
$dates = $matches[3]; // contains char or string
$result = array();
for ($i=0 ; $i<count ($dates) ; $i++) {
if(!array_key_exists($dates[$i], $dateTimeIndex)) {
throw new Exception ("dateTimeIndex is not configured properly, please add this index : [" . $dates[$i] . "]");
}
$result[$dateTimeIndex[$dates[$i]]] = (int)$datei[$i];
}
return $result;
}
A simple sscanf
will parse this into an array. Then you array_combine
it with the list of keys you want.
$time = "1d2h3m";
$result = array_combine(
['day', 'hour', 'minutes'],
sscanf($time, '%dd%dh%dm')
);
print_r($result);
Array
(
[day] => 1
[hour] => 2
[minutes] => 3
)
To break down the sscanf
format used:
%d
- reads a (signed) decimal number, outputs an integerd
- matches the literal character "d"%d
- (as the first)h
- matches the literal character "h"%d
- (as the first)m
- matches the literal character "m" (optional, as it comes after everything you want to grab)It'll also work fine with multiple digits and negative values:
$time = "42d-5h3m";
Array
(
[day] => 42
[hour] => -5
[minutes] => 3
)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With