在PHP中解析日期的字符串

时间:2010-06-16 13:21:40

标签: php datetime parsing nlp

给定一个任意字符串,例如("I'm going to play croquet next Friday""Gadzooks, is it 17th June already?"),您将如何从那里提取日期?

如果这对于太难的篮子而言看起来像是一个很好的候选人,也许你可以建议一个替代方案。我希望能够解析Twitter消息的日期。我要查看的推文将是用户指导此服务的推文,因此可以使用更简单的格式进行指导,但我希望它尽可能透明。你能想到一个好的中间地带吗?

9 个答案:

答案 0 :(得分:12)

如果你有马力,你可以尝试以下算法。我正在展示一个例子,并将繁琐的工作留给你:)

//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")更准确,因为它包含更多单词...即“下周五”将始终比“星期五”更准确。

答案 1 :(得分:6)

我会这样做:

首先检查整个字符串是否为strtotime()的有效日期。如果是这样,你就完成了。

如果没有,请确定字符串中有多少个单词(例如,在空白处拆分)。设这个数字为n。

遍历每个n-1个单词组合并使用strtotime()查看该短语是否为有效日期。如果是这样,您在原始字符串中找到了最长的有效日期字符串。

如果不是,则遍历每个n-2个单词组合并使用strtotime()查看该短语是否为有效日期。如果是这样,您在原始字符串中找到了最长的有效日期字符串。

...依此类推,直到找到有效的日期字符串或搜索每个/单个单词为止。通过找到最长的匹配,您将获得最明智的日期(如果这是有道理的)。由于你正在处理推文,你的字符串永远不会很大。

答案 2 :(得分:2)

使用strtotime php函数。

当然你需要设置一些规则来解析它们,因为你需要摆脱字符串上的所有额外内容,但除此之外,它是一个非常灵活的功能,很可能会帮助你在这里

例如,它可以使用“下周五”和“6月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。 考虑到用户使用正确的拼写,如果有一些(可能超过几个!)这些规则,您很可能会在很高比例的情况下提取正确的日期。

就像有人指出的那样,通过正则表达式和一点耐心,你可以做到这一点。编码中最困难的部分是决定你要解决问题的方式,而不是一旦你知道什么就编码!

答案 3 :(得分:2)

遵循 Dolph Mathews 的想法,并且基本上忽略了我以前的答案,我构建了一个非常好的功能,正是这样做的。它返回它认为匹配日期的字符串,它的unix日期戳,以及日期本身或者用户指定的格式或预定义的格式(F j, Y)。我写了一篇关于它的小帖子Extracting a date from a string with PHP。作为预告片,这是两个示例字符串的输出:

输入“我将在下周五打槌球”

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

输入“Gadzooks,已经是6月17日了吗?”

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

我希望它有所帮助。

答案 4 :(得分:2)

基于 Dolph的建议,我写了一个我认为有用的功能。

{{1}}

你会这样称呼:

parse_date('设定截止日期2017年1月5日',0,0)

答案 5 :(得分:1)

以下可能会执行此操作:

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

可能需要一个循环来检查其他周日或其他格式,或者只是嵌套。

答案 6 :(得分:1)

大多数建议的算法实际上都很蹩脚。我建议使用一些漂亮的正则表达式日期和测试句子。以此为例:

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

我跳了几个月,因为我不确定我是否按照正确的顺序记住它们。

这是最简单的解决方案,但我会比其他基于计算能力的解决方案更好地完成工作。 (是的,它不是一个防止失败的正则表达式,但你明白了)。然后在匹配的字符串上应用strtotime函数。这是最简单,最快速的解决方案。

答案 7 :(得分:1)

您正在寻找的是一个时态表达式解析器。您可以查看the Wikipedia article开始使用。请记住,解析器可能变得非常复杂,因为这确实是语言识别问题。这通常是人工智能/计算语言学领域所解决的问题。

答案 8 :(得分:1)

受到基于Dolph算法的Juan Cortes断开的链接的启发,我继续自己编写了它。请注意,我决定只在第一次成功比赛后返回。

<?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]);
            //echo "<code>".implode(" ", $temp_list)."</code><br/>"; // for visualizing the tests, if you want to see it
            if(strtotime(implode(" ", $temp_list))) return implode(" ", $temp_list);
        }
        array_pop($list);
    }

    return false;
}

输入

$array = array(
        "Gadzooks, is it 17th June already",
        "I’m going to play croquet next Friday",
        "Where was the dog yesterday at 6 PM?",
        "Where was Steve on Monday at 7am?"
);

foreach($array as $a) echo "$a => ".extractDatetime(str_replace("?", "", $a))."<hr/>";

输出

Gadzooks, is it 17th June already
is it 17th June already
it 17th June already
17th June already
June already
already
Gadzooks, is it 17th June
is it 17th June
it 17th June
17th June
Gadzooks, is it 17th June already => 17th June
-----
I’m going to play croquet next Friday
going to play croquet next Friday
to play croquet next Friday
play croquet next Friday
croquet next Friday
next Friday
I’m going to play croquet next Friday => next Friday
-----
Where was Rav Four yesterday 6 PM
was Rav Four yesterday 6 PM
Rav Four yesterday 6 PM
Four yesterday 6 PM
yesterday 6 PM
Where was the Rav Four yesterday at 6 PM? => yesterday 6 PM
-----
Where was Steve Monday 7am
was Steve Monday 7am
Steve Monday 7am
Monday 7am
Where was Steve on Monday at 7am? => Monday 7am
-----