-1

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

 - 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。另外,由于某种原因,当我打印出$1and$2时,它是相同的值。在121212, $1is 1212, $2is1212$3is的情况下12。然而,我只想$1成为121212

4

4 回答 4

1

CPAN 模块Time::ParseDateDateTime可能是您正在寻找的,除了62502模式:

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信息。

于 2013-03-13T05:08:52.990 回答
1

您的任务是模棱两可的,因为您可能无法区分 mmd 和 mdd 或 mdccyy 和 mmddyy。

您在匹配 / 的地方取消了空格或破折号选项。

你没有检查闰年。

这是可行的,但很容易出错;不尝试使用正则表达式如何。

于 2013-03-13T03:04:49.327 回答
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
于 2013-03-13T03:03:19.187 回答
0

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

/(1[012]|0?\d)([-\/ ]?)([12]\d|3[01]|0?\d)\2((19|20)?\d\d)/
于 2013-03-13T03:10:02.550 回答