Regex that validates only normal and leap years in C ++

2

I was trying to validate leap years using regex in C ++.

If the user types 28/02/1900 , it would return valid. But if the same type 29/02/1900 , it would return error.

Searching, I found this regex that compiled but is not validating.

const std::regex pattern("^(?:(?:31(/)(?:0?[13578]|1[02]|(?:Jan|Mar|May|Jul|Aug|Oct|Dec)))|(?:(?:29|30)(/)(?:0?[1,3-9]|1[0-2]|(?:Jan|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec))))(?:(?:1[6-9]|[2-9]\d)?\d{2})$|^(?:29(/)(?:0?2|(?:Feb))(?:(?:(?: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]|(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep))|(?:1[0-2]|(?:Oct|Nov|Dec)))(?:(?:1[6-9]|[2-9]\d)?\d{2})$");

I tried to simplify based on another regex for something like:

const std::regex pattern("(0[1-9]|1[0-9]|2[8|9])[*-. /](0[2]|Feb)[*-. /](19[04|08|12|16])\d{2,2}"); //dd/mm/yyyy

I simplified from this based on the first one:

const std::regex pattern("(0[1-9]|1[0-9]|2[8|9]|3[0|1])[*-. /](0[1-9]|1[0|1|2]|Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)[*-. /](19|20)\d{2,2}"); //dd/mm/yyyy

To conclude I am trying to write a regex that reads both but if the person types more than 29 days for February and 29 days for a non-leap year, it should not validate.

If anyone could help me, I would be grateful.

    
asked by anonymous 10.10.2017 / 23:27

2 answers

8
  

You have the gun, I give you the ammunition, but you decide whether to shoot your own leg or not.

     

I come here to offer you the regex that recognizes leap years, does not everything like the response of @VictorStafusa. My regex also does not have lookahead , so this tends to make it longer

First, leap year definition:

  

multiple year of 400, or if it is a multiple of 4 but not of 100.

Keeping in mind that we are dealing with numbers represented decimally. I'll simplify here and assume that every year has 4 digits. This means that 720 is not possible, but 0720 is.

A multiple of 400 is a multiple of any 4 followed by 00 . So I need an expression that detects multiples of 4 two-digit. A number is a multiple of 4 of 2 digits (or more) in base 10 if:

  • Ending with an even number
  • If the units digit is a multiple of 4, the tens digit must be even
  • If the units digit is not a multiple of 4, then the tens digit must be odd
  • Then we have the following expression to recognize multiples of 4:

    [02468][048]|[13579][26]
    

    To recognize multiples of 400, just by 00 at the end:

    ([02468][048]|[13579][26])00
    

    To be a multiple of 4 but not 100, it is basically that first expression, but the% of% of the tens is a special case, since it only accepts 0 or 4 :

    [2468][048]|[13579][26]|0[48]
    

    To ignore the first few digits:

    ..([2468][048]|[13579][26]|0[48])
    

    Putting it all together:

    ([02468][048]|[13579][26])00|..([2468][048]|[13579][26]|0[48])
    
        
    11.10.2017 / 00:05
    6

    Well, regex are not a good alternative to this problem. Because this is a mathematical problem and regex do not know how to do accounts, they only evaluate repetitions in strings.

    However, as an exercise in curiosity, we will use regex anyway.

    First, let's start with something that recognizes a number from 01 to 28 (days that have in every month):

    (?:0[1-9]|1[0-9]|2[0-8])
    

    Something that recognizes a number from 01 to 12:

    (?:0[1-9]|1[0-2])
    

    Putting the two together:

    (?:0[1-9]|1[0-9]|2[0-8])\/(?:0[1-9]|1[0-2])
    

    For the 30 or 31-day months:

    (?:(?:29|30)\/(?:01|0[3-9]|1[0-2]))|(?:31\/(?:01|03|05|07|08|10|12))
    

    Something that recognizes numbers of years from 1583 :

    (?:[2-9][0-9]{3}|1[6-9][0-9]{2}|159[0-9]|158[3-9])
    

    Putting it all together:

    (?:(?:0[1-9]|1[0-9]|2[0-8])\/(?:0[1-9]|1[0-2])|(?:(?:29|30)\/(?:01|0[3-9]|1[0-2]))|(?:31\/(?:01|03|05|07|08|10|12)))\/(?:[2-9][0-9]{3}|1[6-9][0-9]{2}|159[0-9]|158[3-9])
    

    That was the easy part. This recognizes every day other than February 29.

    On days that are February 29th, day and month are easy:

    29\/02
    

    The last two digits of years that are always lexical:

    (?:04|08|[2468][048]|[13579][26])
    

    So those unfinished years at 00 are leap years:

    (?:[2-9](?:04|08|[2468][048]|[13579][26])|1[6-9](?:04|08|[2468][048]|[13579][26])|159(?:2|6)|158(?:4|8))
    

    These are the years since 1583 ended at 00 and leap:

    (?:16|[2468][048]|[3579][26])00
    

    Combining this, one arrives at all 29 of February since 1583:

    29\/02\/(?:(?:[2-9](?:04|08|[2468][048]|[13579][26])|1[6-9](?:04|08|[2468][048]|[13579][26])|159(?:2|6)|158(?:4|8))|(?:16|[2468][048]|[3579][26])00)
    

    Combining all:

    (?:(?:0[1-9]|1[0-9]|2[0-8])\/(?:0[1-9]|1[0-2])|(?:(?:29|30)\/(?:01|0[3-9]|1[0-2]))|(?:31\/(?:01|03|05|07|08|10|12)))\/(?:[2-9][0-9]{3}|1[6-9][0-9]{2}|159[0-9]|158[3-9])|29\/02\/(?:(?:[2-9](?:04|08|[2468][048]|[13579][26])|1[6-9](?:04|08|[2468][048]|[13579][26])|159(?:2|6)|158(?:4|8))|(?:16|[2468][048]|[3579][26])00)
    
        
    11.10.2017 / 00:08