Как преобразовать "1d2h3m" в массив ( "день" => 1, "час" => 2, "минуты" => 3)?

Есть $time = "1d2h3m";, поэтому я хочу, чтобы это было в массиве вроде array("day" => 1, "hour" => 2,"minutes"=>3), поэтому я попытался с помощью explode()

<?php
   $time = "1d2h3m";
   $day = explode("d", $time);
   var_dump($day); // 0 => string '1' (length=1)
                   // 1 => string '2h3m' (length=4)
?>

Здесь я понятия не имею, как сделать массив вроде array("day" => 1, "hour" => 2,"minutes"=>3)

Ответ 1

Простой sscanf проанализирует это в массиве. Затем вы array_combine со списком нужных вам ключей.

Пример:

$time = "1d2h3m";

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

print_r($result);

Вывод:

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

Чтобы разбить используемый формат sscanf:

  • %d - считывает (подписанное) десятичное число, выводит целое число
  • d - соответствует буквенному символу "d"
  • %d - (как первый)
  • h - соответствует буквенному символу "h"
  • %d - (как первый)
  • m - соответствует буквенному символу "m" (необязательно, поскольку он приходит после всего, что вы хотите захватить)

Он также отлично работает с несколькими цифрами и отрицательными значениями:

$time = "42d-5h3m";
Array
(
    [day] => 42
    [hour] => -5
    [minutes] => 3
)

Ответ 2

Вы должны пойти с регулярным выражением для этого случая

<?php
 $time = "1d2h3m";
 if(preg_match("/([0-9]+)d([0-9]+)h([0-9]+)m/i",$time,$regx_time)){
    $day = (int) $regx_time[1];
    $hour = (int) $regx_time[2];
    $minute = (int) $regx_time[3];
    var_dump($day);
 }
?>

Объяснение:
[0-9]: сопоставьте любые цифры от 0 до 9
[0-9] +: означает, что цифры соответствуют хотя бы одному символу
([0-9] +): означает, чтобы цифры соответствовали хотя бы одному символу и фиксировали результаты
/........../i: установите регистр insenstive для шаблона регулярного выражения, которое вы установили

Regex - это лучший способ лексики и синтаксического анализа. И хорошо изучить регулярное выражение. Почти все языки программирования используют regex

Ответ 3

Настраиваемая функция и самое главное, что вы можете поймать исключение, если вход не сформирован правильно

/**
  * @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;
}

Ответ 4

Другое решение для регулярных выражений

$subject = '1d2h3m';
if(preg_match('/(?P<day>\d+)d(?P<hour>\d+)h(?P<minute>\d+)m/',$subject,$matches))
{
  $result = array_map('intval',array_intersect_key($matches,array_flip(array_filter(array_keys($matches),'is_string'))));
  var_dump($result);
}

Возвращает

array (size=3)
  'day' => int 1
  'hour' => int 2
  'minute' => int 3

Ответ 5

Используйте эту простую реализацию с заменой строки и массивом.

<?php
   $time = "1d2h3m";
   $time=str_replace(array("d","h","m")," " ,$time);
   $time=array_combine(array("day","hour","minute"),explode(" ",$time,3));

   print_r($time);
?>

Ответ 6

Я думаю, что для такой маленькой строки, и если формат всегда будет одним и тем же, вы можете использовать array_push и substr, чтобы извлечь из строки цифры и поместить их в массив.

<?php
$time = "1d2h3m";
$array = array();
array_push($array, (int) substr($time, 0, 1));
array_push($array, (int) substr($time, 2, 1));
array_push($array, (int) substr($time, 4, 1));
var_dump($array);
?>

Ответ 7

В этом подходе используется регулярное выражение для извлечения значений и массива для сопоставления букв со словами.

<?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;
   }

Ответ 8

$d = [];
list($d['day'],$d['hour'],$d['minutes']) = preg_split('#[dhm]#',"1d2h3m");

Ответ 9

Не можете ли вы просто взорвать его 3 раза...

// Define an array
$day = explode("d", $time);
// add it in array with key as "day" and first element as value
$hour= explode("h", <use second value from above explode>);
// add it in array with key as "hour" and first element as value
$minute= explode("m", <use second value from above explode>);
// add it in array with key as "minute" and first element as value

У меня сейчас нет рабочего примера, но я думаю, что это сработает.

Ответ 10

Мы можем также достичь этого, используя str_replace() и explode().

$time = "1d2h3m"; 
$time = str_replace(array("d","h","m"), "*", $time);
$exp_time =  explode("*", $time); 
$my_array =  array(  "day"=>(int)$exp_time[0],
                     "hour"=>(int)$exp_time[1],
                     "minutes"=>(int)$exp_time[2] ); 
var_dump($my_array);

Ответ 11

$time = "1d2h3m";
$split = preg_split("/[dhm]/",$time);
$day = array(
    "day"     => $split[0]
    "hour"    => $split[1]
    "minutes" => $split[2]
);

Ответ 12

Вы можете использовать однострочное решение,

$time = "1d2h3m";
$day = array_combine(
           array("day","hour","months")   , 
           preg_split("/[dhm]/", substr($time,0,-1)  )    
       );

Ответ 13

Здесь есть много отличных ответов, но я хочу добавить еще один, чтобы показать более общий подход.

function parseUnits($input, $units = array('d'=>'days','h'=>'hours','m' => 'minutes')) {
    $offset = 0;
    $idx = 0;

    $result = array();
    while(preg_match('/(\d+)(\D+)/', $input,$match, PREG_OFFSET_CAPTURE, $offset)) {
        $offset = $match[2][1];

        //ignore spaces
        $unit = trim($match[2][0]);
        if (array_key_exists($unit,$units)) { 
            // Check if the unit was allready found
            if (isset($result[$units[$unit]])) {  
                throw new Exception("duplicate unit $unit");
            }

            // Check for corect order of units
            $new_idx = array_search($unit,array_keys($units));
            if ($new_idx < $idx) {
                throw new Exception("unit $unit out of order");             
            } else {
                $idx = $new_idx;
            }
            $result[$units[trim($match[2][0])]] = $match[1][0];

        } else {
            throw new Exception("unknown unit $unit");
        }
    }
    // add missing units
    foreach (array_keys(array_diff_key(array_flip($units),$result)) as $key) {
        $result[$key] = 0;
    }
    return $result;
}
print_r(parseUnits('1d3m'));
print_r(parseUnits('8h9m'));
print_r(parseUnits('2d8h'));
print_r(parseUnits("3'4\"", array("'" => 'feet', '"' => 'inches')));
print_r(parseUnits("3'", array("'" => 'feet', '"' => 'inches')));
print_r(parseUnits("3m 5 d 5h 1M 10s", array('y' => 'years', 
           'm' => 'months', 'd' =>'days', 'h' => 'hours', 
           'M' => 'minutes', "'" => 'minutes', 's' => 'seconds' )));
print_r(parseUnits("3m 5 d 5h 1' 10s", array('y' => 'years', 
           'm' => 'months', 'd' =>'days', 'h' => 'hours',
           'M' => 'minutes', "'" => 'minutes', 's' => 'seconds' )));

Ответ 14

Вы можете использовать этот fn для получения форматированного массива, который также проверяет правильность строки:

function getFormatTm($str)
{
    $tm=preg_split("/[a-zA-z]/", $str);

    if(count($tm)!=4) //if not a valid string
       return "not valid string<br>";
    else
       return array("day"=>$tm[0],"hour"=>$tm[1],"minutes"=>$tm[2]);
}
$t=getFormatTm("1d2h3m");
var_dump($t);

Ответ 15

Этот ответ не 100% относится к определенному формату входной строки из вопроса.

Но он основан на механизме синтаксического анализа PHP (это не мой собственный синтаксический анализ даты).

PHP >= 5.3.0 имеет класс DateInterval.

Вы можете создавать объекты DateInterval из укусов в двух форматах:

$i = new DateInterval('P1DT12H'); // ISO8601 format
$i = createFromDateString('1 day + 12 hours'); // human format

Официальные документы PHP: http://php.net/manual/en/dateinterval.createfromdatestring.php

В формате ISO8601 P означает "период". Формат поддерживает три формы периодов:

  • PnYnMnDTnHnMnS
  • PNW
  • PT

Заглавные буквы означают следующее:

  • P - это обозначение продолжительности (исторически называемое "периодом" ), размещенное в начале представления продолжительности.
  • Y - это обозначение года, которое следует за количеством лет.
  • M - это обозначение месяца, которое следует за количеством месяцев.
  • W - это указатель недели, который следует за значением числа недель.
  • D - это обозначение дня, которое следует за значением числа дни.
  • T - обозначение времени, которое предшествует компонентам времени представление.
  • H - это часовой указатель, который следует за значением числа ч.
  • M - это минутный указатель, который следует за количеством мин.
  • S - это второй указатель, который следует за количеством секунд.

Например, " P3Y6M4DT12H30M5S" представляет собой продолжительность " три года, шесть месяцев, четыре дня, двенадцать часов, тридцать минут и пять секунд".

Подробнее см. https://en.wikipedia.org/wiki/ISO_8601#Durations.

Ответ 16

Один код строки.

   $result = array_combine(array("day", "hour", "minutes"), $preg_split('/[dhm]/', "1d2h3m", -1, PREG_SPLIT_NO_EMPTY));

Ответ 17

Вы можете использовать этот код.

<?php
$str = "1d2h3m";
list($arr['day'],$arr['day'],$arr['hour'],$arr['hour'],$arr['minute'],$arr['minute']) = $str;
print_r($arr);
?>

ВЫХОД

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

DEMO