9

My Question: I found this exercise very challenging. I'm kind stuck on the Date of Birth.

Challenge: Try to come up with the regular expressions to validate the following text strings (don't worry about case insensitivity):

  1. First name — should be composed of standard English letters and between one and ten characters in length.
  2. Middle initial — should be composed of standard English letters and be only one character in length.
  3. Last name — should be composed of standard English letters plus the apostrophe and between two and ten characters in length.
  4. Date of birth - should fall between 1/1/1900 and 12/31/2099, and should be one of the following date formats: dd/mm/yyyy, dd-mm-yyyy, or dd.mm.yyyy.

I was able to come up for the first three names. But I'm stuck on the Date of Birth.

   "^[a-z]{1,10}$",  // First name
   "^[a-z]$",        // Middle initial
   "^[a-z']{2,10}$", // Last name

Please help me.

Mustofa Rizwan
  • 10,215
  • 2
  • 28
  • 43
JeffreyC
  • 625
  • 1
  • 8
  • 19
  • Those requirements for the date format are a bit confusing. In the dates named for the acceptable range, you have the month place before the day (indicated by 12/31) yet in the date formats, the day comes first. Also, the earliest date (1/1/1900) is written as d/m/yyyy. Does the regex need to match single digit values for month and day as well, or would this date appear as 01/01/1900? – CAustin Mar 04 '14 at 00:04
  • Just yesterday I wrote a blog post about matching number-ranges with regex, which applies to the year-portion of your problem (although, I admit, 1900 to 2099 is pretty easy, as stated in some of your answers): http://aliteralmind.wordpress.com/2014/03/02/regex_numeric_range – aliteralmind Mar 04 '14 at 00:26
  • It is not trivial, see my answer here: http://stackoverflow.com/a/3873172/372239 – Toto Mar 27 '14 at 09:32

8 Answers8

13

There are a couple of items to deal with here:

  1. Validating only appropriate values for the day, month and year values
  2. Validating that the correct elements are in the correct place
  3. Validating that the separators match
  4. Validating that it's an actual date

The first looks possible with grouping and or. For example, you could match all values from 1-12 with:

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

And 1900 - 2099 with

(?:19|20)\d\d

The second bit is just a matter of putting the appropriate parts of the pattern in the right place.

The third part can be accomplished with a back reference. First you have a subgroup to match the separator characters like so:

([\/.-])

Next you need to make sure you get the same character again later in the match. That's done by specifying a backslash followed by the number of the group. For example:

\1

Finally we want to make sure that no one specifies 31 June 1925 or 30 February 1994. That is absolutely horrendous to accomplish in regex and should quickly send us running for the hills. Regex isn't the right solution to that problem. So leaving that aside we can solve the first three parts with a regex that looks like:

^(?:0[1-9]|[12]\d|3[01])([\/.-])(?:0[1-9]|1[012])\1(?:19|20)\d\d$

Note the use of ?: to make some of the groupings not get a submatch so that we only have to deal with the submatches we're interested in. Not strictly required, but it makes it clearer. If you left those out the separator would be the second subgroup, not the first.

Coenwulf
  • 1,937
  • 2
  • 15
  • 23
11

For regex for dates, see the link: Regex Tutorial

But I think the example will work.

  "^(0[1-9]|1[012])[-/.](0[1-9]|[12][0-9]|3[01])[-/.](19|20)\\d\\d$" 
Jeff
  • 493
  • 3
  • 19
  • The requested format is `dd/mm/yyyy` not `mm/dd/yyyy`. Also it matches `02/31/1900` – Toto Mar 27 '14 at 09:28
5

@Coenwulf had a great one and well explained, I naturally picked it. But there is actually an error and should be fixed to:

/^(?:0[1-9]|[12]\d|3[01])([\/.-])(?:0[1-9]|1[012])\1(?:19|20)\d\d$/

Otherwise the date won't validate if the month is 10.

The change is in (?:0[1-9]|1[012]), where you should read:

  • (?: ) is a non-capturing group (to allow an expression)
  • 0[1-9] allows a 0 followed by a digit from 1 to 9
  • 1[012] allows a 1 followed by one of the digits 0, 1 or 2
  • the | between the two means 'or'

Hope it helps.

antoni
  • 5,001
  • 1
  • 35
  • 44
4
/^((1[0-2])|[1-9])[/-.](3[0-1]|[1-2]\d|[1-9])[/-.][19|20]\d{2}$/
La-comadreja
  • 5,627
  • 11
  • 36
  • 64
1

For the date of birth, you match on the start of the string, then for the month portion you have a capturing group to match one of 01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11 or 12, followed by another capturing group to match either -, /

For the day portion, you need to capture group to match one of 01, 02, … 29, 30, or 31, followed by capturing group to match either -, / or

Date of birth:

  "^(0[1-9]|1[012])[-/.](0[1-9]|[12][0-9]|3[01])[-/.](19|20)\\d\\d$" 
KJC2009
  • 59
  • 1
  • 17
1

Try

/^((1[0-2])|[1-9])[/-.](3[0-1]|[1-2]\d|[1-9])[/-.][19|20]\d{2}$/
Superman2013
  • 41
  • 10
1

For the date of birth, match on the start of the string, then for the month portion you have a capturing group to match one of 01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11 or 12, followed by another capturing group to match either -, /

I think this example will work.

 "^(0[1-9]|1[012])[-/.](0[1-9]|[12][0-9]|3[01])[-/.](19|20)\\d\\d$" 
1

try this

/^([0-2^([0-2][0-9]|(3)[0-1])(\/)(((0)[0-9])|((1)[0-2]))(\/)\d{4}$/
  • 2
    Thank you for this code snippet, which might provide some limited, immediate help. A [proper explanation](https://meta.stackexchange.com/q/114762/349538) would greatly improve its long-term value by showing why this is a good solution to the problem and would make it more useful to future readers with other, similar questions. Please [edit] your answer to add some explanation, including the assumptions you’ve made. – Şivā SankĂr Feb 15 '19 at 07:09