PHP preg_match constant output

206 views Asked by At

I'm trying to parse out a string that could have multiple values and if one doesn't exist the array is outputting the part I'm looking for up one spot, causing me logic headaches.

What I'm trying to parse: P1DT12H15M, or PT1H5M, or PT15M Basically it's P(Number of Days) T(Number of Hours)(Number of Minutes). The P and T are constant. Here's the match string I have so far:

'/P([0-9]*?)D?T([1-2]?[0-9]?)H?([1-5]?[0-9]?)M?/'

It pulls everything apart, but the array output is not what I'm looking for.

PT2H gives Array ( [0] => PT2H [1] => [2] => 2 [3] => )
PT2H15M gives Array ( [0] => PT2H15M [1] => [2] => 2 [3] => 15 )

But

PT15M gives Array ( [0] => PT15M [1] => [2] => 15 [3] => )

I need that number to be in position 3, if possible.

2

There are 2 answers

0
axiac On

Your input strings looks like time interval specifiers. Let the PHP internal class DateInterval parse them then access the properties of [DateInterval] to get the values you need:

$int = new DateInterval('P1DT12H15M');
print_r($int);

produces:

DateInterval Object
(
    [y] => 0
    [m] => 0
    [d] => 1
    [h] => 12
    [i] => 15
    [s] => 0
    [weekday] => 0
    [weekday_behavior] => 0
    [first_last_day_of] => 0
    [invert] => 0
    [days] =>
    [special_type] => 0
    [special_amount] => 0
    [have_weekday_relative] => 0
    [have_special_relative] => 0
)

You can access the properties directly (they are public):

printf("%d days, %d hours, %d minutes\n", $int->d, $int->h, $int->i);

If you need them as array you can even convert $int to an array and use them this way:

$date = (array)$int;
printf("%d days, %d hours, %d minutes\n", $date['d'], $date['h'], $date['i']);

If you insist, you can even emulate the behaviour of the preg_match() you struggle to create:

$string   = 'P1DT12H15M';
$interval = new DateInterval($string);
$array    = (array)$interval;
$matches  = array_merge(array($string), array_slice(array_values($array), 0, 6));

print_r($matches);

displays:

Array
(
    [0] => P1DT12H15M
    [1] => 0
    [2] => 0
    [3] => 1
    [4] => 12
    [5] => 15
    [6] => 0
)

(use array_slice(..., 3, 6) to keep only the time components)

0
splash58 On
$exp = '/P(?:([0-9]+)D)*T(?:([1-2]?[0-9])H)*(?:([1-5]?[0-9])M)*/';

preg_match($exp, 'PT2H15M', $m); print_r($m);
preg_match($exp, 'PT15M', $m); print_r($m);
preg_match($exp, 'P1DT12H15M',$m); print_r($m);

result

Array
(
    [0] => PT2H15M
    [1] => 
    [2] => 2
    [3] => 15
)
Array
(
    [0] => PT15M
    [1] => 
    [2] => 
    [3] => 15
)
Array
(
    [0] => P1DT12H15M
    [1] => 1
    [2] => 12
    [3] => 15
)

So, you can take $P = m[1], $H= m[2], $M = m[3]