Search code examples
phpdatedate-rangetext-parsing

Parse date range expression where end month is omitted when it is the same as the start month


I have a date field that looks like the following:

$exampleOne = 'Sep 04-08';
$exampleTwo = 'Sep 29-Oct 01';

How can I separate them to become:

$exampleOneResult = {'Sep 04', 'Sep 08'};
$exampleTwoResult = {'Sep 29', 'Oct 01'};

I was thinking to make a loop of splitting '-' first, then splitting ' ' second, but I think that would be too resource heavy?


Solution

  • For a concise and direct approach with fewer temporary variables, pre-hydrate the string to contain two months, then unconditionally explode on the hyphen. Done.

    Pattern:

    ^         #from start of the string
    (\D{4})   #capture four non-digit characters
    \d{2}     #match two digit characters
    -         #match  hyphen
    \K        #forget/release all matched characters
    (?=\d)    #check that the next character is a digit (the month is missing)
    

    The $1 in the replacement injects the month and space from the front of the string into the position immediately after the hyphen without consuming any characters in the process.

    Code: (Demo)

    $examples = [
        'Sep 04-08',
        'Sep 29-Oct 01',
    ];
    
    $result = [];
    foreach ($examples as $example) {
        var_export(
            explode('-', preg_replace('/^(\D{4})\d{2}-\K(?=\d)/', '$1', $example))
        );
        echo "\n";
    }
    

    Output:

    array (
      0 => 'Sep 04',
      1 => 'Sep 08',
    )
    array (
      0 => 'Sep 29',
      1 => 'Oct 01',
    )
    

    Or you can achieve the same result without regex by "left padding" the "to" string with the "from" string because the "from" string will always have all 6 characters and the "to" string will never have less than 2 characters. In other words, the days from the "from" string will ALWAYS be overwritten by the "to" days. Demo

    $result = [];
    foreach ($examples as $example) {
        [$from, $to] = explode('-', $example, 2);
        var_export([$from, str_pad($to, 6, $from, STR_PAD_LEFT)]);
        echo "\n";
    }