显示一系列天数

时间:2014-07-19 15:32:39

标签: php date days

我们说这些数字数组对应于一周中的天数(从星期一开始):

/* Monday - Sunday */
array(1, 2, 3, 4, 5, 6, 7)

/* Wednesday */
array(3)

/* Monday - Wednesday and Sunday */
array(1, 2, 3, 7)

/* Monday - Wednesday, Friday and Sunday */
array(1, 2, 3, 5, 7)

/* Monday - Wednesday and Friday - Sunday */
array(1, 2, 3, 5, 6, 7)

/* Wednesday and Sunday */
array(3, 7)

如何有效地将这些数组转换为所需的字符串,如C风格的注释所示?任何帮助将不胜感激。

4 个答案:

答案 0 :(得分:4)

以下代码应该有效:

<?php
// Create a function which will take the array as its argument
function describe_days($arr){
$days = array("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday");
// Begin with a blank string and keep adding data to it
$str = "";
// Loop through the values of the array but the keys will be important as well
foreach($arr as $key => $val){
// If it’s the first element of the array or ...
// an element which is not exactly 1 greater than its previous element ...
    if($key == 0 || $val != $arr[$key-1]+1){
        $str .= $days[$val-1]."-";
    }
// If it’s the last element of the array or ...
// an element which is not exactly 1 less than its next element ...
    if($key == sizeof($arr)-1){
        $str .= $days[$val-1];
    }
    else if($arr[$key+1] != $val+1){
        $str .= $days[$val-1]." and ";
    }
}
// Correct instances of repetition, if any
$str = preg_replace("/([A-Z][a-z]+)-\\1/", "\\1", $str);
// Replace all the "and"s with commas, except for the last one
$str = preg_replace("/ and/", ",", $str, substr_count($str, " and")-1);
return $str;
}

var_dump(describe_days(array(4, 5, 6)));      // Thursday-Saturday
var_dump(describe_days(array(2, 3, 4, 7)));   // Tuesday-Thursday and Sunday
var_dump(describe_days(array(3, 6)));         // Wednesday and Saturday
var_dump(describe_days(array(1, 3, 5, 6)));   // Monday, Wednesday and Friday-Saturday
?>

答案 1 :(得分:3)

/* Monday - Sunday */
$days1 = [1, 2, 3, 4, 5, 6, 7];

/* Monday - Wednesday and Sunday */
$days2 = [1, 2, 3, 7];

/* Wednesday and Sunday */
$days3 = [3, 7];

/* Monday - Wednesday and Friday - Sunday */
$days4 = [1, 2, 3, 5, 6, 7];

/* Monday - Wednesday, Friday and Sunday */
$days5 = [1, 2, 3, 5, 7];

/* Monday, Wednesday, Friday and Sunday */
$days6 = [1, 3, 5, 7];

// creates logic groups out of flat array
function splitIntoSequences(array $days)
{
    $collection = [];
    do {
        $seq = extractSequence($days);
        $collection[] = $seq;

        $days = array_diff($days, $seq);
    }
    while (!empty($days));

    return $collection;
}

// filters the next sequence
function extractSequence(array $days)
{
    sort($days);

    $seq = [];
    foreach ($days as $day) {
        // seq break
        if (!empty($seq) && $day - 1 != $seq[count($seq) - 1]) {
            return $seq;
        }

        $seq[] = $day;
    }

    return $seq;
}

// removes all unneeded steps from sequences
function cleanupSequences(array $collection)
{
    $cleanedCollection = [];
    foreach ($collection AS $seq) {
        if (count($seq) == 1) {
            $cleaned = [array_pop($seq)];
        } else {
            $cleaned = [array_shift($seq), array_pop($seq)];
        }

        $cleanedCollection[] = $cleaned;
    }

    return $cleanedCollection;
}

// convert whole collection to daynames
function convertToDaynames(array $collection)
{
    $daynameCollection = [];
    foreach ($collection AS $seq) {
        $days = [];
        foreach ($seq as $day) {
            $days[] = numberToDay($day);
        }

        $daynameCollection[] = $days;
    }

    return $daynameCollection;
}

// number to dayname
function numberToDay($weekday)
{
    $relative = sprintf('next Sunday + %d day', $weekday);
    $date = new \DateTime($relative);

    return $date->format('l');
}

// format output
function format(array $collection)
{
    $t = [];
    foreach ($collection as $seq) {
        $t[] = implode(' - ', $seq);
    }

    if (count($t) == 1) {
        return array_pop($t);
    }

    $last = array_pop($t);

    return sprintf('%s and %s', implode(', ', $t), $last);
}

测试电话:

function makeMeHappy(array $seq)
{
    $splitted = splitIntoSequences($seq);
    $cleaned = cleanupSequences($splitted);
    $daynames = convertToDaynames($cleaned);
    return format($daynames);
}


var_dump(makeMeHappy($days1));
// string(15) "Monday - Sunday"

var_dump(makeMeHappy($days2));
// string(29) "Monday - Wednesday and Sunday"

var_dump(makeMeHappy($days3));
// string(20) "Wednesday and Sunday"

var_dump(makeMeHappy($days4));
// string(38) "Monday - Wednesday and Friday - Sunday"

var_dump(makeMeHappy($days5));
// string(37) "Monday - Wednesday, Friday and Sunday"

var_dump(makeMeHappy($days6));
// string(36) "Monday, Wednesday, Friday and Sunday"

答案 2 :(得分:2)

我试过并测试了这个:

/* Monday - Sunday */
$days1 = array(1, 2, 3, 4, 5, 6, 7);

/* Monday - Wednesday and Sunday */
$days2 = array(1, 2, 3, 7);

/* Wednesday and Sunday */
$days3 = array(3, 7);

/* Monday - Wednesday and Friday - Sunday */
$days4 = array(1, 2, 3, 5, 6, 7);

/* Monday - Wednesday, Friday and Sunday */
$days5 = array(1, 2, 3, 5, 7);

/* Monday, Wednesday, Friday and Sunday */
$days6 = array(1, 3, 5, 7);

function displayDays($days = array()) {

    // 1: Create periods and group them in arrays with starting and ending days
    $periods = array();

    $periodIndex = 0;

    $previousDay = -1;
    $nextDay = -1;

    foreach($days as $placeInList => $currentDay) {     
        // If previous day and next day (in $days list) exist, get them.
        if ($placeInList > 0) {
            $previousDay = $days[$placeInList-1];
        }
        if ($placeInList < sizeof($days)-1) {
            $nextDay = $days[$placeInList+1];
        }

        if ($currentDay-1 != $previousDay) {
        // Doesn't follow directly (in week) previous day seen (in our list) = starting a new period
            $periodIndex++;
            $periods[$periodIndex] = array($currentDay);
        } elseif ($currentDay+1 != $nextDay) {
        // Follows directly previous day, and isn't followed directly (in week) by next day (in our list) = ending the period       
            $periods[$periodIndex][] = $currentDay;
            $periodIndex++;
        }
    }
    $periods = array_values($periods);


    // Arrived here, your days are grouped differently in bidimentional array.
    // print_r($periods); // If you want to see the new array's structure

    // 2: Display periods as we want.
    $text = '';
    foreach($periods as $key => $period) {
        if ($key > 0) {
        // Not first period
            if ($key < sizeof($periods)-1) {
            // Not last period either
                $text .= ', ';
            } else {
            // Last period
                $text .= ' and ';
            }
        }

        if (!empty($period[1])) {
        // Period has starting and ending days
            $text .= jddayofweek($period[0]-1, 1).' - '.jddayofweek($period[1]-1, 1);
        } else {
        // Period consists in only one day
            $text .= jddayofweek($period[0]-1, 1);
        }
    }

    echo $text.'<br />';
}

displayDays($days1);
displayDays($days2);
displayDays($days3);
displayDays($days4);
displayDays($days5);
displayDays($days6);

jddayofweek()返回星期几。在那个函数中,0是星期一,6是星期日,这就是&#34; -1&#34;每次我都使用它:你的星期一是1,星期日是7。

答案 3 :(得分:2)

我们可以将数组问题转换为字符串问题,并使用正则表达式(正则表达式)解决方案......间接地通过finite automata检查所有条件和案例。

PS:当我们有短阵列和少数情况时,这种算法结构是安全的,并提供完整的解决方案。

哦是的,我们也可以将周数翻译成另一种语言(参见$ lang参数)!

多语言和正则表达式解决方案

function weekNumbers_toStr($days, $lang='en') {
     $and = array('pt'=>'e', 'en'=>'and');
     $strWeek = array(     // config with more langs!
        'pt'=>array("Segunda", "Terça", "Quarta", "Quinta", "Sexta", 
                  "Sábado", "Domingo"),
        'en'=> array("Monday", "Tuesday", "Wednesday", "Thursday", 
                  "Friday", "Saturday", "Sunday")
     );
     $days = array_unique($days);
     sort($days);
     $seq = preg_replace_callback(  // Split sequence by ",":
        '/0246|024|025|026|135|146|246|02|03|04|05|06|13|14|15|16|24|25|26|35|36|46/',
        function ($m) { return join( ',' , str_split($m[0]) ); },
        join('',$days)
     );
     // split two or more days by "-":
     $seq = preg_replace('/(\d)\d*(\d)/', '$1-$2', $seq);
     $a = explode(',',$seq);
     $last = array_pop($a);
     $n = count($a); 
     // Formating and translating:
     $seq = $n? join(", ",$a): $last;
     if ($last && $n) $seq = "$seq $and[$lang] $last";
     return preg_replace_callback(
        '/\d/',
        function ($m) use (&$strWeek,$lang) { 
           return $strWeek[$lang][$m[0]]; 
        },
        $seq
     );
 } // func

测试:

print "\n".weekNumbers_toStr(array(6,1,2,3,6),'en'); // corrects order and dups
print "\n".weekNumbers_toStr(array(0,1,2,3,6));      // Monday-Thursday and Sunday

print "\n".weekNumbers_toStr(array(3,4,6),'pt');  // Quinta-Sexta e Domingo
print "\n".weekNumbers_toStr(array(3,4,6));       // Thursday-Friday and Sunday

print "\n".weekNumbers_toStr(array(2,3,4,6));  // Wednesday-Friday and Sunday
print "\n".weekNumbers_toStr(array(3,5));      // Thursday and Saturday
print "\n".weekNumbers_toStr(array(0,2,4,6));  // Monday, Wednesday, Friday and Sunday
print "\n".weekNumbers_toStr(array(0));        // Monday
print "\n".weekNumbers_toStr(array());         // (nothing)