ObBot Wgent LiveTree Архив
Архив новостей  Архив публикаций  Разное 

Сложный парсер даты и времени начала и окончания мероприятия, написанных человеком


Страница:  1 2 3

Сложный парсер даты и времени начала и окончания мероприятия, написанных человеком
Простое решение парадокса Ферми
Thank God For The Bomb
Неверные загадки
Распахивание больших картинок на jQuery
Защита пароля от подбора брутфорсом
Тест на вшивость по биологии
Накрутка рекомендательного сервиса
Игра в шахматы на деньги

Люди пишут даты как бык на душу положил. Ко временам у них отношение схожее: могут написать "ЧЧ:ММ", а могут и "ЧЧ-ММ", и даже "ЧЧ/ММ" иногда ухитряются, не задумываясь об отличимости формата времени от формата даты. "11.11.11, 12.12.12" - это 12 часов 12 минут 12 секунд 11 ноября 2011 года или таки 23 часа 11 минут 11 секунд 12 декабря 2012?


А уж коли нужно переводить в текст какой-нибудь календарь или график или какое-нибудь  расписание мероприятий, фантазия человеческая и вовсе границ не знает. Но нет, я не буду даже и пытаться объять необъятное и написать функцию, распознающую написанные человеком  даты и времена лучше, чем распознает другой человек. Ниже идёт пример того, что мой скрипт действительно умеет делать:


30 августа 2018 года в 14:00 -> 30 августа в 14:00
28 июля 2018 года в 10:00 - 18:00 -> 28 июля c 10:00 до 18:00
01 мая 2018 года в 11:00 -> 1 мая в 11:00
18 августа - 14 октября 2018 года в 10:00 - 18:00 -> с 18 августа по 14 октября c 10:00 до 18:00
18 - 31 августа 2018 года в 10:00 - 18:00 -> с 18 по 31 августа c 10:00 до 18:00
02 августа - 04 сентября 2018 года в 10:00-18:00 -> со 2 августа по 4 сентября c 10:00 до 18:00
01 августа - 09 сентября 2018 года в 10:00-18:00 -> с 1 августа по 9 сентября c 10:00 до 18:00
25 июля - 05 августа 2018 года -> с 25 июля по 5 августа
21 - 22 июля 2018 года в 10:00 -> 21 и 22 июля в 10:00
29 - 30 марта 2018 года -> 29 и 30 марта
02 - 06 июля 2018 года -> со 2 по 6 июля
01 - 31 июля 2018 года -> с 1 по 31 июля
05 - 05 июля 2018 года -> 5 июля
14 - 15 апреля 2018 года в 10:00 - 19:00 -> 14 и 15 апреля c 10:00 до 19:00

Это был пример работы выражения FormatDateTimes( dateHuman2Array($s) ), сначала преобразующего написанный человеком набор дат-времён начала-конца мероприятий в массив вида array( array("dat"=>ДАТА, "tim"=>ВРЕМЯ_НАЧАЛА, "end"=>ВРЕМЯ_ОКОНЧАНИЯ) ), а затем форматирующего этот массив обратно в псевдочеловеконаписанный текст.



А вот и сами функции:



function dateHuman2Array($s){
//Преобразует человеком написанные строчки расписания мероприятий типа "01 августа - 09 сентября 2018 года в 9:30-18:45"
//в массив дат-времён начала и окончания (если окончание указано) в формате "YYYY-MM-DD HH:mm:ss"
//возвращает массив array( array("dat"=>ДАТА, "tim"=>ВРЕМЯ_НАЧАЛА, "end"=>ВРЕМЯ_ОКОНЧАНИЯ) )
  $s=preg_replace("/[^0-9а-я-:s]/Usi", "", $s); //иногда люди вставляют в даты довольно странные символы
  $pregDatTim="/^s*(d{1,2})(s+-s+d{1,2}|)s+([а-яё]+)s+(-s+(d{1,2})s+([а-яё]+)s+|)(d{4})s+(|г[^s]*)s*(.*)(s*вs*(d{1,2})[:-](d{1,2})(s*-s*(d{1,2})[:-](d{1,2})|)|)s*$/Usi";
  if( !preg_match($pregDatTim, $s, $m) ) return false;
  $r=array();
  $TimDatStart=strtotime( $m[7]."/".mesyatz2int($m[3])."/".$m[1] );
  if($m[2]) {//найдена дата окончания в том же месяце
$TimDatEnd=strtotime( $m[7]."/".mesyatz2int($m[3])."/".preg_replace("/[^0-9]/Usi", "", $m[2]) ); //найдена дата окончания в том же месяце
  }
  elseif($m[5]){ //найдена дата окончания
if($m[6]) $TimDatEnd=strtotime( $m[7]."/".mesyatz2int($m[6])."/".$m[5] ); //if дата окончания лежит в другом месяце
   else $TimDatEnd=strtotime( $m[7]."/".mesyatz2int($m[3])."/".$m[5] ); //else дата окончания лежит в том же месяце
  } //if найдена дата окончания
  else $TimDatEnd=$TimDatStart; 
  $Start=$End=false;
  if( $m[11] && $m[12]) { //найдено время начала
$Start=$m[11].":".$m[12].":00"; if( $m[14] && $m[15]) $End=$m[14].":".$m[15].":00"; //если найдено время окончания }// if найдено время начала
   for($dT=$TimDatStart; $dT<=$TimDatEnd; $dT+=86400){
$d=date("Y-m-d", $dT);
    $r[]=array("dat"=>$d, "tim"=>$Start, "end"=>$End);
   }//for формирование возвращаемого массива
  return $r;
}//function dateHuman2Array($s)

function FormatDateTimes($DTs){
//преобразует массив дат-времён начал и окончаний мероприятий вида array( array("dat"=>ДАТА, "tim"=>ВРЕМЯ_НАЧАЛА, "end"=>ВРЕМЯ_ОКОНЧАНИЯ) ) в псевдочеловеконаписанный текст
//Препроцессинг: собираем воедино все времена, относящиеся к каждой одной и той же дате
$Ds=array();
foreach($DTs as $DT) $Ds[$DT["dat"]][]=FormatFromTo($DT);
$DTs=array();
foreach($Ds as $key=>$D){
$T=$D[count($D)-1];
unset($D[count($D)-1]);
if(count($D)) $T=implode(", ", $D)." и ".$T;
$DTs[]=array("dat"=>$key, "t"=>$T);
}
// /Препроцессинг завершён
$r=array();
$rd=array();
$Prev=array();
$DTs[]=array("dat"=>false, "t"=>false); // Для концевого завершения, т.к. даты мы берём только из Prev
foreach($DTs as $DT){
if( count($Prev) && ($DT["t"] != $Prev["t"] || $DT["dat"]===false) ){ //Время сменилось либо список закончился
if( count($rd) ) {
$PrevD=false;
$rd1=array();
$StartD=$EndD=false;
$rd[]="";
foreach($rd as $d){ //Обрабатываем массив дат, выловленных для данного времени, и собираем эти даты в группы
if( !$PrevD || $d==date( "Y-m-d", strtotime($PrevD)+24*3600 ) ){
$EndD=$d;
if(!$StartD) $StartD=$d;
} //if день == спустя сутки после предыдущего
else{
$StartT=strtotime($StartD); $EndT=strtotime($EndD);
$ddd=date("d", $StartT)+0;
if( date("m", $EndT)==date("m", $StartT) ){
if( $EndT==$StartT+24*3600 ) $rd1[]='<b>'.(date("d", $StartT)+0).'</b> и <b>'.dateYMD2DmesyatzY($EndD, false).'</b>';
elseif($StartD && $EndD!=$StartD) $rd1[]=($ddd==2?"со":"с").' <b>'.(date("d", $StartT)+0).'</b> по <b>'.dateYMD2DmesyatzY($EndD, false).'</b>'; else $rd1[]='<b>'.dateYMD2DmesyatzY($StartD, false).'</b>'; }
elseif($StartD && $EndD!=$StartD) $rd1[]=($ddd==2?"со":"с").' <b>'.dateYMD2DmesyatzY($StartD, false).'</b> по <b>'.dateYMD2DmesyatzY($EndD, false).'</b>';
else $rd1[]='<b>'.dateYMD2DmesyatzY($StartD, false).'</b>';
$StartD=$EndD=$d;
} //else непрерывность дней прервалась
$PrevD=$d;
}//foreach массив дат для данного времени
$rd=$rd1;
$T=$rd[count($rd)-1];
unset($rd[count($rd)-1]);
if(count($rd)) $T=implode(", ", $rd)." и ".$T;
$r[]=$T.$Prev["t"];
$rd=array();
}
}//if !=
if($DT["dat"] && $DT["dat"]!="0000-00-00") $rd[]=$DT["dat"]; //$rd[]='<b>'.dateYMD2DmesyatzY($DT["dat"], false).'</b>';
$Prev=$DT;
}//foreach DT
return implode("<br /> ", $r);
}//function FormatDateTimes($DTs)

//Пара вспомогательных функций

function mesyatz2int($mesyatz){ //слово "mesyatz" написано транслитом, а не по-английски, чтобы подчеркнуть, что речь идёт о русскоязычных названиях месяцев
$mesyatz=trim($mesyatz);
if( preg_match("/^(январ|)(феврал|)(март|)(апрел|)(ма[йяею]|)(июн|)(июл|)(август|)(сентябр|)(октябр|)(ноябр|)(декабр|)/Usi", $mesyatz, $m) ) for($i=1; $i<13; $i++) if($m[$i]) return ($i<10?"0":"").$i; return false; } //function mesyatz2int($s)
function int2mesyats($dati){
$months=array("месяца", "января", "февраля", "марта", "апреля", "мая", "июня", "июля", "августа", "сентября", "октября", "ноября", "декабря");
return @$months[(int)$dati];
} //function int2mesyats($dati)



 
 
  W-gent and ObBot / Архив / Архив публикаций / Создание сайта©www.ObBot.com

Наш хостинг-провайдер