模式匹配日期

时间:2013-03-13 02:50:29

标签: regex perl

我在尝试匹配日期模式时遇到了麻烦。以下任何日期都是合法的:

 - 121212
 - 4 9 12
 - 5-3-2000
 - 62502
 - 3/3/11
 - 09-08-2001
 - 8 6 07
 - 12 10 2004
 - 4-16-08
 - 3/7/2005

这个日期匹配真正具有挑战性的是,年份不必是4位数(假设2位数年份在21世纪,即02 = 2002年),月份/日期可以写成如果它是一个月的月份,则为0,并且日期可以用空格,短划线或斜线分隔,也可以不用。

这就是我现在所拥有的:
/((((0[13578])|([13578])|(1[02]))[\/-]?\s*(([1-9])|(0[1-9])|([12][0-9])|(3[01])))|(((0[469])|([469])|(11))[\/-]?\s*(([1-9])|(0[1-9])|([12][0-9])|(30)))|((2|02)[\/](([1-9])|(0[1-9])|([12][0-9])))[\/-]?\s*(20[0-9]{2})|([0-9]{2}))/g

这几乎可行,除了现在我不确定我是否假设日期和月份的长度。例如,在121212的情况下,我可能假设月份为1而不是12。此外,出于某种原因,当我打印出$1$2时,它是相同的值。对于121212$11212$21212$312。但是,我只希望$1121212

4 个答案:

答案 0 :(得分:1)

此解决方案处理您提供的所有案例。但解决方案并非万无一失,因为问题含糊不清。例如。我们如何解释日期12502?是1/25/02还是12/5/02?

use 5.010;
while (my $line = <DATA>) {
    chomp $line;
    my @date = $line =~ /
        \A
        ([01]?\d)   # month is 1-2 digits, but the first digit may only be 0 or 1
        [ \-\/]?    # may or may not have a separator
        ([0123]?\d) # day is 1-2 digits
        [ \-\/]?
        (\d{2,4})   # year is 2-4 digits
        \z
    /x;
    say join '_', @date;
}

__DATA__
121212
4 9 12
5-3-2000
12502
3/3/11
09-08-2001
8 6 07
12 10 2004
4-16-08
3/7/2005

答案 1 :(得分:1)

你的任务不明确,因为你可能无法从mdd或mdccyy告诉mmd来自mmddyy。

您在与/.

匹配的地方停止了空格或破折号选项

你没有检查闰年。

这是可行的,但犯错很容易;如何不用正则表达式来做这件事。

答案 2 :(得分:1)

62502模式外,CPAN模块Time::ParseDateDateTime可能正是您要寻找的:

use DateTime;
use Time::ParseDate;

foreach my $str (<DATA>) {
    chomp $str;
    $str =~ tr{ }{/};

    my $epoch = parsedate($str, GMT => 1);
    next unless $epoch; # skip 62502

    my $dt = DateTime->from_epoch ( epoch => $epoch );
    print $dt->ymd, "\n";
}

__DATA__
121212
4 9 12
5-3-2000
62502
3/3/11
09-08-2001
8 6 07
12 10 2004
4-16-08
3/7/2005

拥有DateTime对象后,您可以轻松提取yearmonthday信息。

答案 3 :(得分:0)

根据你给出的信息,这是我能想到的最好的。它匹配所有可能性,并对月/日范围和年份(从1900年到2099年)进行错误检查

/(1[012]|0?\d)([-\/ ]?)([12]\d|3[01]|0?\d)\2((19|20)?\d\d)/