格式化日期

时间:2013-03-13 20:14:31

标签: perl

2012年4月9日可以用以下任何方式编写:

4912
4/9/12
4-9-12
4 9 12
04-9-12
04-09-12
4 9 2012
4 09 2012
(I think you get the point)

对于那些不理解的人,规则是:

1. Dates may or may not have ` `, `-` or `/` between them
2. The year can be written as 2 digits (assumed to be dates in the range of [2000, 2099] inclusive) or 4 digits
3. One digit month/days may or may not have leading zeroes.

你如何解决问题,将日期格式化为04/09/12?

我知道日期可能不明确,即12112可能是12/1/12或1/21/12,但假设可能是最小的月份。

2 个答案:

答案 0 :(得分:2)

这实际上是正则表达式擅长的东西;做出一个假设,继续前进,然后在必要时进行回溯以获得成功的匹配。

s{
    \A 
    ( 1[0-2] | 0?[1-9] )
    [-/ ]?
    ( 3[01] | [12][0-9] | 0?[1-9] )
    [-/ ]?
    ( (?: [0-9]{2} ){1,2} )
    \z
 }
 {
    sprintf '%02u/%02u/%04u', $1, $2, ( length $3 == 4 ? $3 : 2000+$3 )
 }xe;

目前的范围检查虽然不是由月份的价值决定,但应该足以从模棱两可的案例中选出一个好的约会(有好的约会)。

请注意,首先尝试两位数的月份和日期非常重要;否则111111变为1-1-1111,而不是大概是11-11-11。但这意味着11111将更喜欢11-1-11,而不是1-11-11。

如果需要进行有效的月检查,则应在重新格式化后执行。

注意:

s{}{}是使用花括号代替/来分隔正则表达式的部分以避免必须转义/的替换,并且还因为使用成对分隔符允许打开和关闭模式和替换部分,对我来说很好看。

\A匹配匹配字符串的开头; \z匹配结尾。 ^$通常用于此,但在某些情况下可能会略有不同的含义;我更喜欢这些因为它们总是只意味着一件事。

最后的x标志表示这是一个扩展的正则表达式,可以有额外的空格或被忽略的注释,因此它更具可读性。 (字符类中的空格不会被忽略。)e标志表示替换部分不是字符串,而是要执行的代码。

'%02u/%02u/%02u'是一种printf格式,用于获取值并以特定方式格式化它们;见http://perldoc.perl.org/functions/sprintf.html

答案 1 :(得分:1)

安装Date :: Calc

在ubuntu libdate-calc-perl

这应该能够读取所有这些日期(2012年4月9日,2012年4月9日除外),然后以通用格式输出