正则表达式以匹配有效日期

时间:2020-03-05 18:49:50  来源:igfitidea点击:

我正在尝试编写一个验证日期的正则表达式。正则表达式需要匹配以下内容

  • M / D / YYYY
  • MM / DD / YYYY
  • 单位月份的数字可以以前导零开头(例如:2008年3月12日)
  • 单位位数可以以前导零开头(例如:2008年3月2日)
  • 不能包括2月30日或者2月31日(例如:2/31/2008)

到目前为止,我有

^(([1-9]|1[012])[-/.]([1-9]|[12][0-9]|3[01])[-/.](19|20)\d\d)|((1[012]|0[1-9])(3[01]|2\d|1\d|0[1-9])(19|20)\d\d)|((1[012]|0[1-9])[-/.](3[01]|2\d|1\d|0[1-9])[-/.](19|20)\d\d)$

这正确匹配,除了它仍然包括2/30/2008和2/31/2008.

有谁有更好的建议?

编辑:我在RegExLib上找到了答案

^((((0[13578])|([13578])|(1[02]))[\/](([1-9])|([0-2][0-9])|(3[01])))|(((0[469])|([469])|(11))[\/](([1-9])|([0-2][0-9])|(30)))|((2|02)[\/](([1-9])|([0-2][0-9]))))[\/]\d{4}$|^\d{4}$

它与遵循MM / DD / YYYY格式的所有有效月份相匹配。

谢谢大家的帮助。

解决方案

回答

听起来我们为此目的过度使用了正则表达式。我要做的是使用正则表达式来匹配一些日期格式,然后使用单独的函数来验证提取的日期字段的值。

回答

正则表达式不是要验证数字范围的(当它前面的数字恰好是2而前面的数字恰好是6以下时,此数字必须从1到5)。
只需查找正则表达式中数字的放置方式即可。如果我们需要验证日期质量,则将其放入日期对象js / c#/ vb中,然后在其中查询数字。

回答

这不是正则表达式的适当用法。我们最好使用

[0-9]{2}/[0-9]{2}/[0-9]{4}

然后使用高级语言检查范围。

回答

我知道这不能回答问题,但是为什么不使用日期处理例程来检查它是否是有效日期呢?即使我们使用诸如(?!31/0?2)之类的否定超前断言来修改正则表达式(即不匹配31/2或者31/02),我们仍然会有在非leap年接受29 02的问题。以及单个分隔符日期格式。

如果我们想真正验证日期,则问题并不容易,请查看此论坛主题。

有关示例或者更好的方法,请在C#中检查此链接

如果我们使用其他平台/语言,请告诉我们

回答

如果我们要坚持使用正则表达式执行此操作,则建议我们执行以下操作:

( (0?1|0?3| <...> |10|11|12) / (0?1| <...> |30|31) |
  0?2 / (0?1| <...> |28|29) ) 
/ (19|20)[0-9]{2}

这可能使阅读和理解成为可能。

回答

Perl扩展版本

注意使用/ x修饰符。

/^(
      (
        ( # 31 day months
            (0[13578])
          | ([13578])
          | (1[02])
        )
        [\/]
        (
            ([1-9])
          | ([0-2][0-9])
          | (3[01])
        )
      )
    | (
        ( # 30 day months
            (0[469])
          | ([469])
          | (11)
        )
        [\/]
        (
            ([1-9])
          | ([0-2][0-9])
          | (30)
        )
      )
    | ( # 29 day month (Feb)
        (2|02)
        [\/]
        (
            ([1-9])
          | ([0-2][0-9])
        )
      )
    )
    [\/]
    # year
    \d{4}$

  | ^\d{4}$ # year only
/x

原版的

^((((0[13578])|([13578])|(1[02]))[\/](([1-9])|([0-2][0-9])|(3[01])))|(((0[469])|([469])|(11))[\/](([1-9])|([0-2][0-9])|(30)))|((2|02)[\/](([1-9])|([0-2][0-9]))))[\/]\d{4}$|^\d{4}$

回答

可维护的Perl 5.10版本

/
  (?:
      (?<month> (?&mon_29)) [\/] (?<day>(?&day_29))
    | (?<month> (?&mon_30)) [\/] (?<day>(?&day_30))
    | (?<month> (?&mon_31)) [\/] (?<day>(?&day_31))
  )
  [\/]
  (?<year> [0-9]{4})

  (?(DEFINE)
    (?<mon_29> 0?2 )
    (?<mon_30> 0?[469]   | (11) )
    (?<mon_31> 0?[13578] | 1[02] )

    (?<day_29> 0?[1-9] | [1-2]?[0-9] )
    (?<day_30> 0?[1-9] | [1-2]?[0-9] | 30 )
    (?<day_31> 0?[1-9] | [1-2]?[0-9] | 3[01] )
  )
/x

我们可以在此版本中按名称检索元素。

say "Month=$+{month} Day=$+{day} Year=$+{year}";

(未尝试限制年份的值。)

回答

rx{
  ^

  $<month> = (\d ** 1..2)
  { $<month> <= 12 or fail }

  '/'

  $<day> = (\d ** 1..2)
  {
    given( +$<month> ){
      when 1|3|5|7|8|10|12 {
        $<day> <= 31 or fail
      }
      when 4|6|9|11 {
        $<day> <= 30 or fail
      }
      when 2 {
        $<day> <= 29 or fail
      }
      default { fail }
    }
  }

  '/'

  $<year> = (\d ** 4)

  $
}

在使用它来检查输入后,值可以在$ /中使用,也可以分别以$$ month,$$ day和$ year来使用。 (这些只是用于访问$ /中的值的语法)

未尝试检查年份,或者在非leap年不匹配2月29日。

回答

略有不同的方法可能对我们有用,也可能没有用。

我在php中。

与之相关的项目的日期永远不会早于2008年1月1日。因此,我输入了"日期"并使用strtotime()。如果答案> = 1199167200,那么我有个对我有用的日期。如果输入的内容看起来不像日期,则返回-1. 如果输入null,则它确实会返回今天的日期号,因此我们需要首先检查非null输入。

适用于我的情况,也许也适用于情况?