Подтвердить что ты не робот

Разбор строки для дат в PHP

Для произвольной строки, например ("I'm going to play croquet next Friday" или "Gadzooks, is it 17th June already?"), как вы собираетесь извлечь даты оттуда?

Если это выглядит хорошим кандидатом на слишком сложную корзину, возможно, вы могли бы предложить альтернативу. Я хочу иметь возможность анализировать сообщения Twitter для дат. Твиты, на которые я смотрю, будут теми, на которые пользователи направляют эту службу, поэтому их можно было бы использовать в более удобном формате, однако я бы хотел, чтобы он был максимально прозрачным. Есть ли хорошая средняя точка, о которой вы могли бы подумать?

4b9b3361

Ответ 1

Если у вас есть лошадиная сила, вы можете попробовать следующий алгоритм. Я показываю пример и оставляю вам утомительную работу:)

//Attempt to perform strtotime() on each contiguous subset of words...

//1st iteration
strtotime("Gadzooks, is it 17th June already")
strtotime("is it 17th June already")
strtotime("it 17th June already")
strtotime("17th June already")
strtotime("June already")
strtotime("already")

//2nd iteration
strtotime("Gadzooks, is it 17th June")
strtotime("is it 17th June")
strtotime("17th June") //date!
strtotime("June") //date!

//3rd iteration
strtotime("Gadzooks, is it 17th")
strtotime("is it 17th")
strtotime("it 17th")
strtotime("17th") //date!

//4th iteration
strtotime("Gadzooks, is it")
//etc

И мы можем предположить, что strtotime("17th June") точнее, чем strtotime("17th") просто потому, что содержит больше слов... т.е. "в следующую пятницу" всегда будет более точным, чем "пятница".

Ответ 2

Я бы сделал это следующим образом:

Сначала проверьте, является ли целая строка допустимой датой с помощью strtotime(). Если это так, все готово.

Если нет, определите, сколько слов в вашей строке (например, разделите на пробелы). Пусть это число равно n.

Прокрутите каждую комбинацию слов n-1 и используйте strtotime(), чтобы увидеть, является ли фраза допустимой датой. Если это так, вы нашли самую длинную допустимую строку даты в своей исходной строке.

Если нет, перебирайте каждую n-2 комбинацию слов и используйте strtotime(), чтобы увидеть, является ли фразу правильной датой. Если это так, вы нашли самую длинную допустимую строку даты в своей исходной строке.

... и так далее до тех пор, пока вы не найдете действительную строку даты или не выполните поиск каждого отдельного слова. Найдя самые длинные совпадения, вы получите самые информированные даты (если это имеет смысл). Поскольку вы имеете дело с твитами, ваши строки никогда не будут огромными.

Ответ 3

Используйте функцию strtotime php.

Конечно, вам нужно будет установить некоторые правила для их анализа, поскольку вам нужно избавиться от всего дополнительного содержимого в строке, но помимо этого, это очень гибкая функция, которая, скорее всего, поможет вам здесь.

Например, он может принимать строки типа "следующая пятница" и "15 июня" и возвращает соответствующую временную метку UNIX для даты в строке. Я предполагаю, что если вы рассмотрите некоторые основные правила, такие как поиск "следующего X" и названия недели и месяца, вы сможете это сделать.

Если бы вы могли найти "следующую пятницу" из "Я собираюсь играть в крокет в следующую пятницу", вы можете извлечь дату. Похоже, забавный проект! Но имейте в виду, что strtotime использует только английские фразы и не будет работать с каким-либо другим языком.

Например, правило, которое обнаружит все случаи "Следующий день недели", будет таким же простым, как:

$datestring = "I'm going to play croquet next Friday";

$weekdays = array('monday','tuesday','wednesday',
                  'thursday','friday','saturday','sunday');

foreach($weekdays as $weekday){
    if(strpos(strtolower($datestring),"next ".$weekday) !== false){
        echo date("F j, Y, g:i a",strtotime("next ".$weekday));
    }
}

Это вернет дату следующего дня недели, указанного в строке, если она будет следовать правилу! В этом конкретном случае выход был June 18, 2010, 12:00 am. С некоторыми (возможно, более чем несколькими!) Из этих правил вы, скорее всего, выберете правильную дату в большом проценте случаев, учитывая, что пользователи используют правильную орфографию.

Как было указано, с регулярными выражениями и небольшим терпением вы можете это сделать. Самая сложная часть кодирования - это решение, каким образом вы собираетесь приблизиться к своей проблеме, а не кодировать ее, как только вы знаете, что!

Ответ 4

Следуя идее Dolph Mathews и в основном игнорируя мой предыдущий ответ, я построил довольно приятную функцию, которая делает именно это. Он возвращает строку, которая, по ее мнению, соответствует дате, дате ее unix и самой дате либо с указанным пользователем форматом, либо с предопределенным (F j, Y). Я написал небольшую запись об этом на Извлечение даты из строки с помощью PHP. В качестве тизера здесь вывод двух примерных строк:

Вход: "Я буду играть в крокет в следующую пятницу"

Output: Array ( 
           [string] => "next friday",
           [unix] => 1276844400,
           [date] => "June 18, 2010" 
        )

Вход: "Gadzooks, это уже 17 июня?"

Output: Array ( 
           [string] => "17th june",
           [unix] => 1276758000,
           [date] => "June 17, 2010" 
        )

Я надеюсь, что это поможет кому-то.

Ответ 5

Основываясь на предложении Dolph's, я написал функцию, которая, как мне кажется, служит цели.

public function parse_date($text, $offset, $length){

  $parseArray = preg_split( "/[\s,.]/", $text);
  $dateTest = implode(" ", array_slice($parseArray, $offset, $length == 0 ? null : $length));

  $date = strtotime($dateTest);

  if ($date){
    return $date;
  }

  //make the string one word shorter in the front
  $offset++;

  //have we reached the end of the array?
  if($offset > count($parseArray)){

    //reset the start of the string
    $offset = 0;

    //trim the end by one
    $length--;

    //reached the very bottom with no date found
    if(abs($length) >= count($parseArray)){
      return false;
    }
  }

  //try to find the date with the new substring
  return $this->parse_date($text, $offset, $length);
}

Вы бы назвали это следующим образом:

parse_date ('Установка даты выполнения 5 января 2017 года сейчас, 0, 0)

Ответ 6

Это может сделать следующее:

$months = array(
                    "01" => "January", 
                    "02" => "Feberuary", 
                    "03" => "March", 
                    "04" => "April", 
                    "05" => "May", 
                    "06" => "June", 
                    "07" => "July", 
                    "08" => "August", 
                    "09" => "September", 
                    "10" => "October", 
                    "11" => "November", 
                    "12" => "December"
                );

$weekDays = array(
                    "01" => "Monday", 
                    "02" => "Tuesday", 
                    "03" => "Wednesday", 
                    "04" => "Thursday", 
                    "05" => "Friday", 
                    "06" => "Saturday", 
                    "07" => "Sunday"
                );

foreach($months as $value){
    if(strpos(strtolower($string),strtolower($value))){
        \\ extract and assign as you like...
    }
}

Возможно, выполните цикл нот, чтобы проверить другие недели или другие форматы или просто вложить.

Ответ 7

Большинство предлагаемых алгоритмов на самом деле довольно хромает. Я предлагаю использовать какое-нибудь хорошее регулярное выражение для дат и тестирования предложения с ним. Используйте это в качестве примера:

(\d{1,2})? 
((mon|tue|wed|thu|fri|sat|sun)|(monday|tuesday|wednesday|thursday|friday|saturday|sunday))?
(\d{1,2})? (\d{2,4})?

Я пропустил месяцы, так как не уверен, что я помню их в правильном порядке.

Это самое простое решение, но я сделаю эту работу лучше, чем другие решения на основе вычислительной мощности. (И да, это вряд ли надежное регулярное выражение, но вы понимаете). Затем примените функцию strtotime в строке соответствия. Это самое простое и быстрое решение.

Ответ 8

То, что вы ищете, - это анализатор временных выражений. Вы можете посмотреть статью в Википедии, чтобы начать. Имейте в виду, что синтаксические анализаторы могут стать довольно сложными, потому что это действительно проблема распознавания языка. Обычно это проблема, решаемая полем искусственного интеллекта/вычислительной лингвистики.

Ответ 9

Вдохновленный неработающей ссылкой Хуана Кортеса, основанной на алгоритме Дольфа, я решил написать ее сам

<?php
function extractDatetime($string) {
    if(strtotime($string)) return $string;
    $string = str_replace(array(" at ", " on ", " the "), " ", $string);
    if(strtotime($string)) return $string;

    $list = explode(" ", $string);
    $first_length = count($list);
    for($j=0; $j < $first_length; $j++) {
        $original_length = count($list);
        for($i=0; $i < $original_length; $i++) {
            $temp_list = $list;
            for($k = 0; $k < $i; $k++) unset($temp_list[$k]);
            if(strtotime(implode(" ", $temp_list))) return implode(" ", $temp_list);
        }
        array_pop($list);
    }

    return false;
}