0

I'm new to regex and need one to accept (and validate the date) only the dd-mm-yyyy format, with leading zeros for single-digit days or months and only hyphens. I have been able to modify the code given by Ofir Luzon's response here to only allow hyphens but am not able to completely achieve the leading zeros part. Also searched a lot of regex libraries but most solutions either do not validate dates or they allow single digits in the dd and mm parts. Here's the regex:

^(?:(?:31(-)(?:0?[13578]|1[02]))\1|(?:(?:29|30)(-)(?:0?[13-9]|1[0-2])\2))(?:(?:1[6-9]|[2-9]\d)?\d{2})$|^(?:29(-)0?2\3(?:(?:(?:1[6-9]|[2-9]\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00))))$|^(?:0?[1-9]|1\d|2[0-8])(-)(?:(?:0?[1-9])|(?:1[0-2]))\4(?:(?:1[6-9]|[2-9]\d)?\d{2})$

So this accepts dd-mm-yyyy, d-mm-yyyy and dd-m-yyyy, dd-mm-yy, d-m-yy,dd-m-yy, d-mm-yy and validates date, but how to make it restrict to exactly two digits for dd and mm AND four digits for yyyy?

I'm able to understand that the quantifiers for previous tokens need to be changed but am not able to figure out how.

Niels Abildgaard
  • 2,662
  • 3
  • 24
  • 32
Neha Kul
  • 11
  • 1
  • 4
    Is there any chance of using a date-parsing function in the language that the date needs to be validated in to find out if the date is valid? Could this be a case of ["I know, I'll use regular expressions." Now they have two problems."](https://blog.codinghorror.com/regular-expressions-now-you-have-two-problems/)? – Andrew Morton Feb 27 '22 at 17:07
  • "_how to make it restrict to two digits_" - well, turn `0?` into `0`, since `?` is also a quantifier. – AmigoJack Feb 27 '22 at 20:45
  • @AndrewMorton yes it is! :P – Neha Kul Feb 28 '22 at 11:15
  • @AmigoJack did that for all the instances of ```0?``` but doesn't seem to work. The third instance I can't figure out how to modify. – Neha Kul Feb 28 '22 at 11:21
  • What language are you writing the regular expression in? Your approach to the problem seems to be to start with someone else's incredibly complex expression, which I don't think is a good approach for this sort of problem. I think you would be able to ask a better question if you started from something simple you wrote yourself. Check out tools like https://regex101.com/ which can give you quick feedback on the problems you are trying to solve. – Niels Abildgaard Feb 28 '22 at 14:34
  • @NielsAbildgaard, I'm using this regex in an xlsform as a constraint so that we can enable the beneficiaries to enter dates in the dd-mm-yyyy format instead of the yyyy-mm-dd format enforced in ODK. True, I did try to reverse-engineer a pro's regex but was pressed for time. Anyway, I've split my question into day, month and year for now and am working forward to create the regex from scratch. I'm using regex101.com and regexper (which is mind-blowing btw) to both understand complex expressions and make my own now. – Neha Kul Feb 28 '22 at 18:01
  • If it helps, you could use `=MID(A1,7,4) & "-" & MID(A1,4,2) & "-" & MID(A1,1,2)` to get the reverse of the date (in cell A1), so the text dd-mm-yyyy would give the text yyyy-mm-dd. – Andrew Morton Mar 02 '22 at 11:20
  • If you're talking about validating a date as in "Feb 30 is invalid because Feb doesn't have 30 days", then that's not what regexes do. Use a date library to do that. – Andy Lester Mar 07 '22 at 17:02

2 Answers2

0

Here is a suggestion which accepts days from 00-31, months from 00-12 and years from 0000-2999, insisting on 2, 2 and 4 figures.

^([0-2][0-9]|3[01])-(0[0-9]|1[0-2])-[0-2][0-9]{3}$

This does not check for months with less than 31 days. You would do well to use the built-in date functions of whatever language you are working in which will be able to check this.
Modified to include improvements from AmigoJack. 7 characters less in the regex string without changing the matching.
Thank you AmigoJack

  • The `-` doesn't need escaping. Most round brackets are redundant. Range `[0-1]`- really? – AmigoJack Mar 07 '22 at 13:42
  • @AmigoJack the range `[0-1]` goes with 3 to make days in the month 30 and 31. I either allow 0-2 & 0-9 to make 1-29 and then 3 & 0-1 to make 30 & 31. Even with this you could declare a date 00-00-0000. To be honest dates are best dealt with by built in functions. –  Mar 07 '22 at 13:54
  • You're missing the regex point: it could be `[01]` right away - no need to make it a range just because it's a class. Your regex would look cleaner as `^([0-2][0-9]|3[01])-(0[0-9]|1[0-2])-[0-2][0-9]{3}$` – AmigoJack Mar 07 '22 at 14:07
0

The following pattern will match strings between "01-01-0000" and "31-12-9999"

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

However, the string still needs to be validated in the programming language.

Because this pattern doesn't care about how many days there are in a month.
And a pattern that could even account for February, with consideration for the leap years, would be overly complex.

^(?:0[1-9]|1[0-9]|2[0-8])-(?:0[1-9]|1[0-2])-[0-9]{4}$|^(?:(?:31-(?:0[13578]|1[02]))-|(?:(?:29|30)-(?:0[13-9]|1[0-2])-))(?:(?:1[6-9]|[2-9][0-9])[0-9]{2})$|^(?:29-02-(?:(?:(?:1[6-9]|[2-9][0-9])(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00))))$
LukStorms
  • 28,916
  • 5
  • 31
  • 45