Парсинг строки для дат в PHP

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

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

22
задан Gordon 16 June 2010 в 13:51
поделиться

7 ответов

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

//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 («17 июня») более точен, чем strtotime («17th» ) просто потому, что он содержит больше слов ... т.е. «следующая пятница» всегда будет более точным, чем «пятница».

12
ответ дан 29 November 2019 в 05:24
поделиться

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

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

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

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

1
ответ дан 29 November 2019 в 05:24
поделиться

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

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

Например, он может принимать такие строки, как «следующая пятница» и «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));
    }
}

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

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

2
ответ дан 29 November 2019 в 05:24
поделиться

Я бы сделал это так:

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

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

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

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

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

6
ответ дан 29 November 2019 в 05:24
поделиться

Что-то вроде следующего могло бы сделать это:

$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...
    }
}

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

1
ответ дан 29 November 2019 в 05:24
поделиться

Следуя идее Дольфа Мэтьюса и игнорируя мой предыдущий ответ, я создал довольно хорошую функцию, которая делает именно это. Он возвращает строку, которая, по его мнению, соответствует дате, ее метке даты 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" 
        )

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

2
ответ дан 29 November 2019 в 05:24
поделиться

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

1
ответ дан 29 November 2019 в 05:24
поделиться
Другие вопросы по тегам:

Похожие вопросы: