-5

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,但假设可能是最小的月份。

4

2 回答 2

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

于 2013-03-13T20:54:32.253 回答
1

安装日期::Calc

在 ubuntu 上 libdate-calc-perl

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

于 2013-03-13T20:17:41.607 回答