简体   繁体   中英

Fairly simple regex question in PHP

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.

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";

There really isn't any easy way to simplify this. The problem is that you are building a regular expression which forces you to test on zero no matter what. You might be better off converting $date into a true date with mktime and then use that in your query.

$date1 = mktime(0,0,0, substr($date, 0, 2), substr($date, 2, 2));
$sqlquery = "select * from table WHERE table_date == $date1";

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

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.

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 (ie 28, 30, 31 days)

  2. Leap years

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

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

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM