lovelycesar Posted March 28, 2012 Share Posted March 28, 2012 Hello, I would like to write a function that lookup a birthday throughout a string for either dd/mm/yy or dd/mm/yyyy formats. How can I do that with preg_match? Thank you. Quote Link to comment Share on other sites More sharing options...
ragax Posted March 28, 2012 Share Posted March 28, 2012 Hi lovelycesar, For speed, I adapted the core expression from the RegexBuddy library, then added some code. Displaying all the pieces for you, just take those you need: Input: is there a date like 07/03/12 or 31/12/2008 in here? Code: <?php $regex=',(0[1-9]|[12][0-9]|3[01])/(0[1-9]|1[012])/((?:19|20)?[0-9]{2}),'; $string='is there a date like 07/03/12 or 31/12/2008 in here?'; $size=preg_match_all($regex, $string, $m); for ($i=0;$i<$size;$i++) { echo "Date # ".($i+1).": ".$m[0][$i]."<br />"; echo "Day / Match # ".($i+1).": ".$m[1][$i]."<br />"; echo "Month / Match # ".($i+1).": ".$m[2][$i]."<br />"; echo "Year / Match # ".($i+1).": ".$m[3][$i]."<br />"; } ?> Output: Date # 1: 07/03/12 Day / Match # 1: 07 Month / Match # 1: 03 Year / Match # 1: 12 Date # 2: 31/12/2008 Day / Match # 2: 31 Month / Match # 2: 12 Year / Match # 2: 2008 Note that this is NOT a date validator: for instance, it will match 31 November, even though November only has 30 days. Let me know if this is what you are looking for and if you have any questions! Quote Link to comment Share on other sites More sharing options...
.josh Posted March 28, 2012 Share Posted March 28, 2012 You are right, regex cannot tell whether the date is valid or not, and since it cannot do that, there's no point in doing even most of what you did, because you will have to validate it by some other means anyways. So all you really *need* is something like this: ~[0-9]+/[0-9]+/[0-9]+~ Quote Link to comment Share on other sites More sharing options...
.josh Posted March 28, 2012 Share Posted March 28, 2012 sidenote @ ragax: you use commas for pattern delimiters? eww ... that makes for unnecessary escaping should you need to for instance do [0-9]{1,10} Quote Link to comment Share on other sites More sharing options...
ragax Posted March 28, 2012 Share Posted March 28, 2012 Hi .josh, Truly nice to hear from you, I enjoy your posts a lot. you use commas for pattern delimiters? eww ... that makes for unnecessary escaping Thankfully not, because I tend to use delimiters that don't need escaping, depending on the expression within. Usually either commas, tildes or hashes. As you know, whichever delimiter you choose, it may need escaping sometimes. Commas are part of the syntax, so they certainly need escaping more often than tildes. On an esthetic level I like commas a lot, as they let the regex stand out like a building over the horizon. I like tildes a lot too. Hashes are a bit blocky for my taste. To me #Hashes# feel like SHOUTING. And slashes tend to degenerate into wiggle art. \/\/ there's no point in doing even most of what you did I don't want to get into an argument with you, but "no point" seems a bit strong. The expression does get us in the ballpark of something that is very close to a date, except for odd cases like 31/11. IMO, whether this is helpful is not, neither of us can judge. It's for the OP to say, depending on his needs. Not knowing his exact needs, I made something that seemed close to his question, offering to help if that was not what he was looking for. What you offered could be exactly what he needs, I cannot say. For instance, he could be looking at input where he knows that all strings of the xx/xx/xx format are dates perfectly formed on a dd/mm/yy pattern, so that we don't need to validate anything, and your solution is perfect. Or he could have a mixture of perfectly formed dates (again no validation needed) but in a variety of formats, such as mm/dd/yy, dd/mm/yy and dd/mm/yyyy, and be looking for a way to fish out the two formats he indicated in the post. Another note: in my experience, imperfect, "best guess" matching is often a reality when you look at long texts. For instance is 07/01/12 January 7, or July first? You have probably noticed that the board gets loads of requests to match an email address. And none of the email address checkers can truly ensure that you have a valid email address. Knowing this, should we just look for (stuff)@(stuff)? Or try to get in the ballpark? That depends on the what we know about the input and the on needs of the user. I'm certainly not attached the expression, I never am---always delighted to see someone coming up with something better or pointing out potential improvements. And this is one of the rare cases when I didn't even craft a regex from scratch (I tweaked something out of the RB library), so I don't have a strong feel for the "balance" of the expression---how it would feel in the hand if it were a hammer. Btw, did you notice that I used your benchmark() function on a recent post? Love it, thanks for that. I used to do my own home-made benchmarking in a way that wasn't nearly so elegant. Sorry for the long message, I just love talking about regex! Not faulting your expression in any way, just a little chat about shades of grey. Wishing you a fun day. Quote Link to comment Share on other sites More sharing options...
Psycho Posted March 28, 2012 Share Posted March 28, 2012 I'm certainly not attached the expression . . . Yet you felt the need to write a couple paragraphs to defend it? jk But, I agree with josh. The difficulty in trying to craft a RegEx to find "valid" dates is not worth the effort. Simply use the regex to pull "possible" date matches and then validate that they are valid using some other means, e.g. checkdate() Besides, by trying to inject validation into the expression it is actually modifying invalid inputs into valid inputs. If a user wanted to enter a date of 2/3/2011 and accidentally entered 2/3/20011, the RegEx you provided would not capture the last '1' and would find a "valid" date of 2/3/2001. The same problem exists with the beginning of the matches. Following josh's method, just capture any possible matches THEN use a proper method to validate the matches. Building upon josh's expression, I made two changes. 1) I used \d instead of 0-9 and 2) I captured the month, day, year parts as separate values expressly for the purpose of running them through checkdate() //Find possible matches preg_match_all("#([\d]+)/([\d]+)/([\d]+)#", $INPUT, $matches, PREG_SET_ORDER); //Find matches that are VALID dates and put into array $valid_dates = array(); //Array to hold all valid dates foreach($matches as $match) { if(checkdate ($match[1], $match[2], $match[3])) { //Save the date to the array of valid dates. //Can convert to timestamp or specific format as needed $valid_dates[] = $match[0]; } } Also, if you wanted to also allow dates that use a dash as the delimiter (e.g. 2-15-2003) you could use this expression "#([\d]+)[/|-]([\d]+)[/|-]([\d]+)#" Quote Link to comment Share on other sites More sharing options...
ragax Posted March 28, 2012 Share Posted March 28, 2012 Yet you felt the need to write a couple paragraphs to defend it? Not to defend it, but to lay out the pros and cons of various methods depending on the input and the user's needs. I am not attached to it, that would make me a complete idiot. I'm curious, after reading my post, does it really sound like I am attached to that regex? If so, I have a lot to learn about expressing myself. :'( I like your solution. Simple and elegant. Of course we still don't know much about the OP's input and his actual needs. Wishing you all a fun day. Quote Link to comment Share on other sites More sharing options...
ragax Posted March 28, 2012 Share Posted March 28, 2012 By the way, if you guys are in a debating mood (Wednesdays sometimes seem to trigger that), I'd really appreciate your thoughts, input, musings, insights, focus and raves on this thread. It needs some senior blood. Quote Link to comment Share on other sites More sharing options...
lovelycesar Posted March 29, 2012 Author Share Posted March 29, 2012 Thank @ragax, and especially @Psycho, for preg_match() + checkdate() combination. Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.