Php – Preg Match circumflex ^ in php


I cant quite get my head around what the ^ is doing in my preg_match.

 if (preg_match('~^(\d\d\d\d)(-(\d{1,2})(-(\d{1,2}))?)?$~', trim($date), $dateParts)) {
   echo the $dateparts and do some magic with them
 } else {
   tell me the date is formatted wrong

As I see it this is looking to see if the $date matches the format which I read as
4 decimals – 1 or 2 decimals – 1 or 2 decimals

if it does match then the IF statement displays the date, if it doesn't then it gives an error of incorrect date formatting.

However just passing it the year
$date = '1977' with nothing else (no day or month) it still goes through as true and displays the dateparts, I would thought it would throw an error?

Can someone point out what I'm missing in the regular expression? I'm guessing it's the ^ or possibly the ?$ at the end may mean only match part of it?

Best Solution

There is no need to group absolutely everything. This looks nicer and will do the same:

preg_match('~^\d{4}(-\d{1,2}(-\d{1,2})?)?$~', trim($date), $dateParts)

This also explains why "1977" is accepted - the month and day parts are both optional (the question mark makes something optional).

To do what you say ("4 decimals - 1 or 2 decimals - 1 or 2 decimals"), you need to remove both the optional groups:

preg_match('~^\d{4}-\d{1,2}-\d{1,2}$~', trim($date), $dateParts)

The "^" and "$" have nothing to do with the issue you are seeing. They are just start-of-string and end-of-string anchors, making sure that nothing else than what the pattern describes is in the checked string. Leave them off and "blah 1977-01-01 blah" will start to match.