我需要用正则表达式验证格式为dd/mm/yyyy的日期字符串。

这个正则表达式验证dd/mm/yyyy,但不验证像31/02/4500这样的无效日期:

^(0?[1-9]|[12][0-9]|3[01])[\/\-](0?[1-9]|1[012])[\/\-]\d{4}$

什么是有效的正则表达式来验证支持闰年的dd/mm/yyyy格式?


当前回答

另一种答案,根据月(mm)和年(yyyy)验证日(dd)(即,在闰年也验证2月29日),并允许年范围从0001到9999(根据公历,0000是无效年)

^(?:(?:(?:0[1-9]|[12]\d|3[01])/(?:0[13578]|1[02])|(?:0[1-9]|[12]\d|30)/(?:0[469]|11)|(?:0[1-9]|1\d|2[0-8])/02)/(?!0000)\d{4}|(?:(?:0[1-9]|[12]\d)/02/(?:(?!0000)(?:[02468][048]|[13579][26])00|(?!..00)\d{2}(?:[02468][048]|[13579][26]))))$

其他回答

这里我为dd/mm/yyyy写了一个,其中分隔符可以是-之一。,/年范围0000-9999。

它处理闰年,是为正则表达式风格设计的,支持查找头,捕获组和反向引用。d/m/yyyy等无效。如果需要,在[-.,/]中添加分隔符

^(?=\d{2}([-.,\/])\d{2}\1\d{4}$)(?:0[1-9]|1\d|[2][0-8]|29(?!.02.(?!(?!(?:[02468][1-35-79]|[13579][0-13-57-9])00)\d{2}(?:[02468][048]|[13579][26])))|30(?!.02)|31(?=.(?:0[13578]|10|12))).(?:0[1-9]|1[012]).\d{4}$

测试regex101;作为Java字符串:

"^(?=\\d{2}([-.,\\/])\\d{2}\\1\\d{4}$)(?:0[1-9]|1\\d|[2][0-8]|29(?!.02.(?!(?!(?:[02468][1-35-79]|[13579][0-13-57-9])00)\\d{2}(?:[02468][048]|[13579][26])))|30(?!.02)|31(?=.(?:0[13578]|10|12))).(?:0[1-9]|1[012]).\\d{4}$"

解释道:

(?x) # modifier x: free spacing mode (for comments)
     # verify date dd/mm/yyyy; possible separators: -.,/
     # valid year range: 0000-9999

^    # start anchor

# precheck xx-xx-xxxx,... add new separators here
(?=\d{2}([-.,\/])\d{2}\1\d{4}$)

(?:  # day-check: non caturing group

  # days 01-28
  0[1-9]|1\d|[2][0-8]| 

  # february 29d check for leap year: all 4y / 00 years: only each 400
  # 0400,0800,1200,1600,2000,...
  29
  (?!.02. # not if feb: if not ...
    (?!
      # 00 years: exclude !0 %400 years
      (?!(?:[02468][1-35-79]|[13579][0-13-57-9])00)

      # 00,04,08,12,... 
      \d{2}(?:[02468][048]|[13579][26])
    )
  )|

  # d30 negative lookahead: february cannot have 30 days
  30(?!.02)|

  # d31 positive lookahead: month up to 31 days
  31(?=.(?:0[13578]|10|12))

) # eof day-check

# month 01-12
.(?:0[1-9]|1[012])

# year 0000-9999
.\d{4}

$ # end anchor

参见SO正则表达式常见问题解答;如果失败了,请告诉我。

下面是regex的另一个版本,它可以匹配以下任何日期格式,并允许省略前导零:

Regex: ^(0 - 3) ?[0 - 9][0 - 3] ?[0 - 9]。(?:[0 - 9]{2})?[0 - 9] {2} $

匹配:

1/1/11或1.1.11或1-1-11:true 01/01/11或01.01.11或01-01-11:true 01/01/2011或011.01.2011或01-01-2011:true 01/1/2011或01.1.2011或01-1-2011:true 1/11/2011或1.11.2011或1-11-2011:true 1/11/11或1.11.11或1-11-11:true 11/1/11或11.1.11或11-1-11:true

Debuggex演示

import re
expression = "Nov 05 20:10:09 2020"
reg_ex = r'((Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) ([0-2][0-9]|(3)[0-1]) (([0-1][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])) (\d{4}))'
assert re.fullmatch(reg_ex, expression), True

对给定例子的解释

11月=一组可能的月份,即(Jan|Feb|Mar|Apr|五月|六月|七月|八月|九月|十月|十一月|十二月) 05年=天即一组有效。([0 - 9][0]| (3)(0 - 1)) 20:10:09 =获得有效时间:一组([0 - 9][0 - 1]| 2(0 - 3)),分钟:([0 - 9][0 - 5])和秒:([0 - 9][0 - 5]) 2020 =获取年份的一组,即(\d{4}))

我认为最好的方法是使用Moment.js的isValid()方法,指定格式并使用严格的解析。

正如moment.js文档所说

从2.3.0版本开始,您可以为最后一个参数指定一个布尔值 使Moment使用严格解析。严格解析要求 格式和输入完全匹配,包括分隔符。

value = '2020-05-25';
format = 'YYYY-MM-DD';
moment(value, format, true).isValid() // true

python的简单函数

def is_valid_date(date_text):
    pattern = re.compile('\d{4}-\d{2}-\d{2}$')
    return pattern.match(date_text)