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

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


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

Скрипт голосовалки
Скрипт телефонного справочника
О рейтингах
Туристическая палатка для жаркого климата
Скрипт бронирования мест для турагентств
Газета Наро-Фоминский Вестник о своём новом сайте
Скрипт транслитерации
Статья в газете Мой Город Обнинск

Люди пишут даты как бык на душу положил. Ко временам у них отношение схожее: могут написать "ЧЧ:ММ", а могут и "ЧЧ-ММ", и даже "ЧЧ/ММ" иногда ухитряются, не задумываясь об отличимости формата времени от формата даты. "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

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