我在尝试匹配日期模式时遇到了麻烦。以下任何日期都是合法的:
- 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
,$1
为1212
,$2
为1212
,$3
为12
。但是,我只希望$1
为121212
。
答案 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::ParseDate和DateTime可能正是您要寻找的:
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对象后,您可以轻松提取year
,month
和day
信息。
答案 3 :(得分:0)
根据你给出的信息,这是我能想到的最好的。它匹配所有可能性,并对月/日范围和年份(从1900年到2099年)进行错误检查
/(1[012]|0?\d)([-\/ ]?)([12]\d|3[01]|0?\d)\2((19|20)?\d\d)/