ASP.NET日期正则表达式验证器 99/99/2012

4

我有下面这个正则表达式日期验证器,但它允许以下日期:

"99/99/2012"

不确定为什么,如果有人知道如何更改正则表达式以检查以上内容,请告诉我。

日期格式如下:06/05/2012 mm/dd/yyyy

正则表达式:

^(((0?[1-9]|1[012])/(0?[1-9]|1\d|2[0-8])|(0?[13456789]|1[012])/(29|30)|(0?[13578]|1[02])/31)/(19|[2-9]\d)\d{2}|0?2/29/((19|[2-9]\d)(0[48]|[2468][048]|[13579][26])|(([2468][048]|[3579][26])00)))$

你可以在客户端使用JS验证,参考http://codecorner.galanter.net/2010/07/20/javascript-isdate-validate-date-according-browser-locale/。作为额外的奖励,支持各种语言环境。 - Yuriy Galanter
@Trekstuff:或者更好的是,一个 .Net 正则表达式验证器 :) - Jeremy
@Jeremy - CompareValidator 可以自动进行数据类型检查。 - Justin Morgan
1
谢谢@JustinMorgan。这是个不错的主意。 - Jeremy
@StevieB - 现在我看了一下,我发现你张贴的正则表达式和我想出来的正则表达式之间有相似之处。你的不允许99/99/2012,但是它过于冗长而且存在问题。首先,它允许1920-9999年的年份;但更重要的是,我不知道为什么 |(([2468][048]|[3579][26])00) 要在那里。 - Justin Morgan
3个回答

3
我看到这些模式中存在许多复杂化。您的日期格式实际上非常简单。我认为您正在采用错误的方法,忽略了28天月份和31天月份之间的重叠部分。
在我进一步解释之前,让我指出,除非您被限制使用正则表达式,否则有更好的方法来解析和验证日期。最好的选择是DateTime.TryParseExact,它专门用于此。如果您正在使用WebForms,您只需使用Operator =“DataTypeCheck”Type =“Date”CompareValidator即可。
既然我说了这些神奇的话,让我们谈论正则表达式模式。
改变您看待此问题的方式。确实,并非所有月份都包含31天甚至30天,但有多少个月份包含28天?

...所有的日期! 因此,如果您想匹配四月和五月,您不需要覆盖4月1日至30日,然后再覆盖5月1日至31日。您可以编写一个模式来覆盖任一月份的前30天,然后单独匹配5月31日。结果类似于[45]/([012]?[1-9]|[123]0)|5/31,长度只有原来的一半。

请考虑这个模式,为了清晰起见进行了扩展:

^(
( #First, we'll cover months and days for a normal year. Forget leap years 
  #for a second.
  (
     (?<month>0?[1-9]|1[012])      #First we account for up to 28 days,
     /(?<day>[01]?[1-9]|10|2[0-8]) #which ALL months have.
  )
  |
  (
     (?<month>0?[13-9]|1[012])     #Every month but February has at
     /(?<day>29|30)                #least 30 days, so cover that.
  )
  |
  (
     (?<month>0?[13578]|1[02])     #Cover the 31st day for months
     /(?<day>31)                   #that have one.
  )
)

/(?<year>(1[89]|20)[0-9]{2})  #Any year between 1800 and 2099.

|  #Normal years: Done. Now we just need to cover February 29, 
   #and only for leap years.

(?<month>0?2)
/(?<day>29)
/(?<year>
      (1[89]|20)      #Century doesn't matter, since 100 is divisible by 4.
      (
        [24680][048]  #If the decade is even, leap years end in [048].
      |                            
        [13579][26]   #If the decade is odd, leap years end in 2 or 6.
      )
  )
)$

我们完成了。强制使用月/日/年格式,验证现有日期,并且代码短小易读。以下是压缩版本:

^(((0?[1-9]|1[012])/([01]?[1-9]|10|2[0-8])|(0?[13-9]|1[012])/(29|30)|(0?[13578]|1[02])/31)/(1[89]|20)[0-9]{2}|0?2/29/(1[89]|20)([24680][048]|[13579][26]))$

编辑:

由于这是.NET,您可以使用回顾先行断言来缩短代码:

 ^(
    (?!(0?[2469]|11)/31)
    (?!0?2/(29|30))
    (?<month>0?[1-9]|1[012])
    /
    (?!0?0/)
    (?<day>[012]?[0-9]|3[01])
    /
    (?<year>(1[89]|20)[0-9]{2})
  |
    (?<month>0?2)/(?<day>29)
    /
    #Years ending in 00 are only leap years if they're divisible by 400:
    (?!1[89]00)  
    (?<year>(1[89]|20) ( [24680][048] | [13579][26] ) )
 )$

一个可能非常微小的问题是它错误地验证了 2/29/1900。除此之外,它是一个不错、干净的日期验证器。 - saluce
@saluce - 哇,我不得不去维基百科查了一下。 很好的发现!由于这是.NET,可以通过在最后一个“year”组之前添加“(?!1[98]00)”来修复它。 - Justin Morgan

2
您可以使用这个正则表达式:
  • 日期格式为 MM/DD/YYYY
  • 验证从 1800 年到 9999 年的任何日期
  • 考虑了闰年
  • 可接受的格式:MM/DD/YYYY、M/DD/YYYY、MM/D/YYYY、M/D/YYYY
This is a regular expression for validating a date in the format of "MM/DD/YYYY".
有点令人生畏,但我多年来一直成功地使用它。
你可以使用这个在线表达式测试器进行测试。
享受吧!

2

考虑另一个选择...

我喜欢简单的正则表达式,但是复杂的很难验证和维护。

你能否编写自己的验证器并使用 DateTime.TryParseExact() 完成工作呢?

有关详细信息,请参见http://msdn.microsoft.com/en-us/library/ms131044.aspx

(untested)

// this is inside a custom validator

DateTime d;

// get dateString from the control
if (DateTime.TryParseExact(dateString, 
                           "MM/dd/yyyy",
                           CultureInfo.InvariantCulture,
                           DateTimeStyles.None,
                           out d)
{
     // valid dateString
}
else
{
    // invalid dateString
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接