tags:

views:

412

answers:

9

Ok, i'm a regex doofus. I only ever learn enough to get me by, but i would like to know how to do the below regex without using a php ternary operator in the middle of it. Also it may be ugly but it works...

'^". $date[0].(($date[0] == 0)?'?':'').$date[1]."[/.-]".$date[2].(($date[2] == 0)?'?':'').$date[3]."'";

uhm. as you can see im using a ternary operator to test if the date contains a 0. if it does.. then it can be ignored, if not then its a 1 or 2 and do not ignore. i'm sure there is a way to write this with just regex? If you know how then please tell me and i will be forever greatful. Also, just incase you wondering this is a regex in a mysql query.

A: 
for($i = 0; $i < 3; $i++) {
    $date[i] = preg_replace($date[i], '0', '');
}

That vanishes any zero.

Check the PHP documentation, it has tons of nice functions. www.php.net

eipipuz
I think i need to explain myself a bit better. i need to test for a zero and also without a zero. Lets say someone entered a birthday in the database but they entered it "6/6/87", then someone else entered another birthday as "06/06/87". the regex has to match both those birthdays. if i just outright do away with the 0 it wont match the second. also, this cannot be done in php as its a mysql query:$sql = "SELECT * FROM clients WHERE birthday REGEXP '^". $date[0].(($date[0] == 0)?'?':'').$date[1]."[/.-]".$date[2].(($date[2] == 0)?'?':'').$date[3]."'";
A: 

I'd recommend not having so much conditional logic built into a single statement that generates the regex. Even if there was a way to implement this as a native regex expression, I doubt it would be any more readable. If the goal is make this snippet more readable, I'd suggest conditionally choosing between different regex expressions or conditionally building the various parts in separate steps, then stitch them together.

dellsala
+1  A: 
JD
ahhh! and now you've hit upon why i'm using regex in a SQL query! you see... all the dates in the database are different, they are entered as strings and with no checking on them, some look like "5.3.2001" or "5-2-82" or even "1/1/83". so i cant use mktime. i was originally pulling all the records out running some php and then mktime on then but it proved to be too cpu intensive. the current way (the above regex nonsense) is extremely quick.
Have you considered converting those text fields to real MySQL DATE fields? When you are parsing dates each time you run a query then of course the query is slow.
Rene Saarsoo
+2  A: 

Are you looking for this? match[1] is the month, match[2] is the day and match[3] is the year

$regex = '#(0?[1-9]|1[0-2])[-/]([0-2]?[1-9]|3[01])[-/](19|20)?\d\d)#';

You have a couple problems here.

First, never ever put a text into a database that you haven't made sure is formatted correctly. The fact that the dates are in the database with and without the 0's is a problem. Why aren't the dates in datetime fields where the database would make sure they are formatted correctly?

Second, the regex above only works in the US where 'mm/dd/yyyy' dates are used. Support for other date formats is impossible if you are tied to that regex.

Third, why are you doing this in the database? Your example is WHERE birthday regex something.... That means you have this date before you are passing it to mySQL. So fix the date in PHP first:

$date = strtotime($_GET['date']);
$sql = "select blah From blah WHERE birthday = '$date' blah";
jmucchiello
I know you are absolutely, undeniably, spastically correct. But alas, i didnt design this database. I can pull the data out convert it and drop it back in.. but the other multitude of scripts that runn off this database might not like what ive done. infact i know they wont.
Also your third point. i mentioned above that the dates look like "5.3.2001" or "5-2-82" or even "1/1/83". i'd need to have at least 6 different WHERE clauses to catch the data i want. what ive written in regex works better with one query.. and this point would also be solved if the data in the database was formatted correctly as datetime.
A: 

JDany has a better solution, but the regex you are looking for is:

    Month         /            Day               /     Year
(0?[1-9]|1[0-2])[/-](0?[1-9]|[1-2][0-9]|3[0-1])[/-](19|20)?\d\d)

Note this regex doesn't handle/validate situations such as:

  1. Months and their corresponding days (i.e. 28, 30, 31 days)

  2. Leap years

Ryan Schumacher
A: 

Good responses so far with regular expression solutions.

Here's another approach -- use the native PHP function strtotime() to normalize the string. It's not perfect, but then neither is a regex solution when dealing with the many formats people might use as dates.

Here's how I would start to attack this:

<?php

// improve strtotime by eliminating dash ambiguity
function strtotimePlus($string) {
    $bads = array('-');
    $goods = array('/');
    return strtotime(str_replace($bads,$goods,$string));
}

// return date in fomat YYYY-MM-DD
function myDateFormat($timeformat) {
    return date("Y-m-d",$timeformat);
}

// convert free-form date string to YYYY-MM-DD
function betterDate($string) {
    return myDateFormat(strtotimePlus($string));

}

// samples from examples mentioned on the thread.
$dates = array();
$dates[] = "6/6/87";
$dates[] = "06/06/87";
$dates[] = "5.3.2001";
$dates[] = "5-2-82";
$dates[] = "1/1/83";

foreach($dates as $date) {
    print $date . " becomes " . betterDate($date) . "<br />";
}

Output:

6/6/87 becomes 1987-06-06
06/06/87 becomes 1987-06-06
5.3.2001 becomes 2001-03-05
5-2-82 becomes 1982-05-02
1/1/83 becomes 1983-01-01
artlung
A: 

Thankyou all for your answers!

A few things to note:
1) i didnt design this database, nor want to make any drastic changes to it.
2) i know very well how to convert strings to dates and vice-versa and all that jazz.
3) what i want to know is if there is a regex operator/expression that can do away with my ternary statement in the middle of it.

I realise i wasnt very clear. I have birthdays of all formats in the database, its a large database. I am pulling dates out of the database two weeks before the birthday of the client.
So..! i take the current date add 14 to it and i would have "17/06/09" this is the date i need to check against the 2000+ dates in the database. this date IS formatted nicely. i like nice things. specially dates. nice dates. anyways....

i need to check my date against the mish mash in the database and the only ways i know of checking this against the database is by
A) pulling every record out, formatting the crappy date correctly and then checking it against mine (which is what i was doing... very cpu intensive)
B) having a regex clause in my sql and retrieving only dates that match my specifications.

Is my logic sound? I Hope so. If not then please point out the obvious to me and i will send you some candy*.




*Imaginary candy

A: 

Don't mean to get downvoted for jumping on fix-the-underlying-problem, but...

If you have all these varying date formats right now, that seems to me to mean that the other apps are fine with the varying formats, and can parse, understand, or at least present the date in whatever form it's in as a string. So, as a string, the other apps that use this data can accept it in any of the forms it's now in.

So it seems to me, that if all the date data continued to be strings, but just happened to all be in one particular layout (say, the international YYYY-MM-DD), that all the other apps would be just as happy with this format as any other, and any script (such as yours) which had to parse the actual value could do so more simply.

So, my question is, are you allowed to scrub and reformat the strings, keeping them strings, so they all look the same? I mean run a cleanup job before your job (either as a separate maintenance task, or just before you work with the data) which checks if a date is in your format, and reformats it and stores it back in the database as a string in the best format if it's not.

Jason Catena
A: 

A separate question about your goal of finding two weeks earlier than the date in the database. How do you know that the user input a day or a month first, if both values are less than 12? For a date like 1/5/06, how do you know whether the user meant 1 May or 5 January? I think you have to solve this, or at least make a decision about it, before you can subtract 14 days.

Jason Catena