Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert "1d2h3m" to ["day" => 1, ”hour” => 2,"minutes"=>3]

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?

like image 244
David Jaw Hpan Avatar asked Sep 22 '15 04:09

David Jaw Hpan


3 Answers

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;
   }
like image 66
user2182349 Avatar answered Sep 18 '22 12:09

user2182349


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;
}
like image 40
Halayem Anis Avatar answered Sep 19 '22 12:09

Halayem Anis


A simple sscanf will parse this into an array. Then you array_combine it with the list of keys you want.

Example:

$time = "1d2h3m";

$result = array_combine(
    ['day', 'hour', 'minutes'],
    sscanf($time, '%dd%dh%dm')
);

print_r($result);

Output:

Array
(
    [day] => 1
    [hour] => 2
    [minutes] => 3
)

To break down the sscanf format used:

  • %d - reads a (signed) decimal number, outputs an integer
  • d - 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
)
like image 31
user3942918 Avatar answered Sep 18 '22 12:09

user3942918