Search code examples
phprangetext-parsingdayshyphenation

Convert consecutive comma-separated days into hyphenated day ranges


I am trying to compact an expression of individual days into a shorter expression including hyphen-separate ranges.

Examples:

  • mon,tue,wed,thu,fri,sat
    to be:
    mon-sat
  • mon,tue,wed,fri,sat
    to be
    mon-wed,fri-sat

My coding attempt:

function dayrange($days){
    $days = explode(",", str_replace(" ","",$days));
    return reset($days) . "-" . end($days);
}

How can I shorten the multi-day expression so that consecutive days are merged into a range of days?


Solution

  • Basically, I would approach this by:

    1. Converting the days to corresponding numeric values
    2. Turning the array of numbers into a string with ranges
    3. Converting the numbers in the string back into days of the week

    I wrote some code to do that:

    /**
     * Convert an array of numbers to a string containing ranges and single values
     * @param array $numbers an array of numbers
     * @return string
     */
    function compressNumbers($numbers) {
        $result = array();
        sort($numbers);
        $previousValue = reset($numbers);
        $startValue = $previousValue;
        foreach ($numbers as $value) {
            if ($value > $previousValue + 1) {
                if ($startValue == $previousValue) {
                    $result[] = $startValue;
                } else {        
                    $result[] = $startValue . '-' . $previousValue;
                }
                $startValue = $value;
            }
            $previousValue = $value;
        }
        if ($startValue == $previousValue) {
            $result[] = $startValue;
        } else {        
            $result[] = $startValue . '-' . $previousValue;
        }
        return implode(',', $result);
    }
    
    /*
     * Creates an array with values the three letter representation for days of the 
     * week and keys the corresponding numeric representation.
     *
     * @return array
     */
    function createLookupNumberToDay() {
        $date = strtotime('now');
        $lookup = array();
        for ($i = 1; $i <= 7; $i++) {
            $lookup[date('w', $date)] = date('D', $date);
            $date = strtotime('+1 day', $date);
        }
        return $lookup;
    }
    
    /*
     * Converts a string listing days separated by commas into 
     * an array with values the numeric value for the corresponding
     * day of the week.
     *
     * @param string $days
     * @return array
     */
    function convertDaysToNumbers($days) {
        $result = array();
        $daysArray = explode(",", str_replace(" ","",$days));
        foreach ($daysArray as $day) {
            $result[] = date('w', strtotime($day));
        }
        return $result;
    }
    
    /*
     * Converts the numbers in a string to the corresponding 3-letter day of the
     * week abbreviation.
     *
     * @param string $string
     * @return string
     */
    function convertNumbersToDays($string) {
        $lookup = createLookupNumberToDay();
        return str_replace(array_keys($lookup), $lookup, $string);
    }
    
    function convert($string) {
        return (convertNumbersToDays(compressNumbers(convertDaysToNumbers($string))));
    }
    
    echo convert('mon,tue,wed,thu,fri,sat');
    echo '<br />';
    echo convert('mon,tue,wed,sat');
    echo '<br />';