我正在尝试将单个日期的表达式压缩为较短的表达式,包括连字符分隔的范围。
例子:
-
mon,tue,wed,thu,fri,sat
:mon-sat
-
mon,tue,wed,fri,sat
待mon-wed,fri-sat
我的编码尝试:
function dayrange($days){
$days = explode(",", str_replace(" ","",$days));
return reset($days) . "-" . end($days);
}
如何缩短多天表达式,以便将连续天数合并为天数范围?
基本上,我会通过以下方式解决这个问题:
- 将天数转换为相应的数值
- 将数字数组转换为带范围的字符串
- 将字符串中的数字转换回星期几
我写了一些代码来做到这一点:
/**
* 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 />';
还没有测试过这个,但应该给你一个好的开始。它也处理周包装。
function dayrange($days){
$wdays = array("mon","tue","wed","thu","fri","sat","sun");
$indays = explode(",", str_replace(" ","",$days)); // expand the list to an array
$retstr = array_shift($indays); // get the first date
$curpos = array_search($retstr, $wdays); // current position in the wdays array
$intv = 0; // interval between days to avoid mon-tue like output
foreach($indays as $d) {
if($d == $wdays[$curpos]) {
$curpos = ($curpos++) % 7; // this will take care of wrapping.
$intv++;
} else {
$retstr.= ($intv > 1 ? "-".$d:",".$d); // use appropriate join
$intv = 0; // reset interval
}
}
if($intv > 0) { // if anything was left deal with the end.
$retstr.= ($intv > 1 ? "-".$d:",".$d);
} else {
$retstr.= ",".$d;
}
return ($retstr);
}
-
将查找定义为常量,以便轻松确定每天的顺序位置。
-
在逗号上分解字符串并迭代日期值。
-
如果结果字符串为空,则添加不带分隔符/粘附符的日期。
-
如果日期是连续定位的日期,则可能会删除追加的昨天子字符串(如果使用连字符附加),然后附加连字符和日期。
-
如果日期不是连续定位的日期,则附加逗号和日期。
代码:(演示)
define('DAYS', array_flip(['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun']));
function condenseDays(string $days): string
{
$result = '';
foreach (explode(',', $days) as $day) {
if (!$result) {
$result .= $day;
} elseif (DAYS[$day] === DAYS[$yesterday] + 1) {
$result = str_replace("-$yesterday", '', $result) . "-$day";
} else {
$result .= ",$day";
}
$yesterday = $day;
}
return $result;
}
echo condenseDays('mon,tue,wed,thu,fri,sat') . "'n";
echo condenseDays('tue,thu,fri,sun') . "'n";
echo condenseDays('mon,tue,wed,fri,sat,sun') . "'n";
echo condenseDays('mon,thu,sun') . "'n";
echo condenseDays('tue,wed,fri,sat') . "'n";
echo condenseDays('mon,wed,fri,sun') . "'n";
echo condenseDays('mon,tue,thu,fri,sat,sun');
输出:
mon-sat
tue,thu-fri,sun
mon-wed,fri-sun
mon,thu,sun
tue-wed,fri-sat
mon,wed,fri,sun
mon-tue,thu-sun
<小时 />或者,如果您更愿意使用蛮力方法,您可以将所有相邻日期的逗号替换为连字符,然后使用正则表达式删除连续多天的"胆量"。
代码:(演示)
define(
'PAIRS',
[
[
'mon,tue',
'tue,wed',
'wed,thu',
'thu,fri',
'fri,sat',
'sat,sun'
],
[
'mon-tue',
'tue-wed',
'wed-thu',
'thu-fri',
'fri-sat',
'sat-sun'
]
]
);
function condenseDays(string $days): string
{
return preg_replace(
'/-'K[^,]+-/',
'',
str_replace(PAIRS[0], PAIRS[1], $days)
);
}
<小时 />最偷偷摸摸/最不容易理解的版本,其中值得范围的逗号由相邻的字母而不是 3 个字母的日期标识。
代码:(演示)
function condenseDays(string $days): string
{
return preg_replace(
'/-'K[^,]+-/',
'',
str_replace(
['n,t', 'e,w', 'd,t', 'u,f', 'i,s', 't,s'],
['n-t', 'e-w', 'd-t', 'u-f', 'i-s', 't-s'],
$days
)
);
}