MortenMoulder
MortenMoulder

Reputation: 6648

Regex to match ddmmyy with leap year as well?

I have made a regex, which matches all months perfectly. Well, perfectly as far as I can see. It matches 01-end of each month, and I cannot seem to generate a false month, unless I enter something like the 32nd of March, which is an invalid date.

Anyway, what I need to do is match the last yy of the regex. If yy ends in a number that can be divided by 4, such as 20, 24, 16, etc, it should ONLY make 2902yy valid. Since I am not checking yyyy, I cannot check if the year is 1900 or 2000, which both ends in 00. Here you can see my current regex:

(((((0[1-9]|1[0-9]|2[0-9]|30)|31)(0[13789]|(10|12)))|(((0[1-9]|1[0-9]|2[0-9]|30))(0[34569]|11))|(((0[1-9]|1[0-9]|2[0-7])|(28|29))02))(0?[0-9]|[1-9][0-9]){2})

Check out my regex and matches here: http://regexr.com/3buc2

Should not match:
290291 because there is no leap year ending in xx91

Should match:
290292 because there is a leap year in 1992/1892/1792

Get what I mean? How can I possibly do that to my regex? Also, can my regex be optimized? \d instead of [0-9] could be done, but it's slower because it matches numbers in different encodings too, and I only need to match 0-9.

Upvotes: 0

Views: 653

Answers (1)

tripleee
tripleee

Reputation: 189357

Using regular expressions for this is madness, or at least borderline. But here is a sketch at a solution.

Days 00 through 28 should always be okay.

Day 30 should be okay if the month is not 02.

Day 31 should be okay if the month is not 02, 04, 06, 09, or 11.

Day 29 should be okay if the month is not 02 or the year is a leap year.

Since you only have two digits for the year, we assume you only want to operate in the current century. The leap years are the years which are divisible by 4. (There are some complications, but they do not apply in this century, because 2000 is evenly divisible by 400 as well as by 100.)

So we can enumerate the years which are leap years: 00, 04, 08, 12, 16, 20, ...

If the first digit in the two-digit year is an even number, then the year is a leap year if the second digit is 0, 4, or 8.

If the first digit is odd, the year is a leap year if the second digit is 2 or 6.

([01][0-9]|2[0-8])(0[0-9]|1[0-2])[0-9][0-9]|
30(0[013-9]|1[0-2])[0-9][0-9]|
31(0[13578]|1[02])[0-9][0-9]|
29((0[013-9]|1[0-2])[0-9][0-9]|02([0246][048]|[13579][26]))

Note that you will need a different regex for the years 1900-1999 because the leap years were different then (in particular, 1900 was not a leap year, because it is not divisible by 400.)

Upvotes: 2

Related Questions