tags:

views:

56

answers:

6

The best way to explain my problem is to just show you.

Input String:

/04-11-2010/12:45/

Regular Expression to get date and time parts:

preg_match('@/(\d\d)-(\d\d)-(\d\d\d\d)/(\d\d):(\d\d)/@', $input, $matches);

PHP Matches Array:

Array
(
    [0] => /01-11-2010/12:45/
    [1] => 01
    [2] => 11
    [3] => 2010
    [4] => 12
    [5] => 45
)

Now the above regex works perfectly at getting the individual component parts that represent the date and time in the input string.

The problem is that the time part needs to be optional without bringing down the entire regular expression.

Problem Input String:

/04-11-2010//

PHP Matches Array

Array
(
)

Basically what I need to be returned by the matches array is:

Array
(
    [0] => /01-11-2010/12:45/
    [1] => 01
    [2] => 11
    [3] => 2010
    [4] => 
    [5] => 
)

Note array elements 4 and 5 still need to exist but return empty.

+1  A: 

Make the second part optional:

'@/(\d\d)-(\d\d)-(\d\d\d\d)/(?:(\d\d):(\d\d))?/@'

Here a non-capturing group (?:…) is used that cannot be referenced and thus doesn’t change the matching groups.

Gumbo
If you do that, the first ( after the / will generate a new array entry, won't it? Or is that what the (? after the / is for? Was that English?
No, it won't. That's what ?: does - it makes it a non-capturing group. Which means a group that can be used to make it optional (? as in this case) or repeated etc. but it won't be captured as part of the return value.
Brenton Alker
the point is, [4] and [5] should be there in any case.
stereofrog
A: 

I'm not a php-head, but how about:

preg_match('@/(\d\d)-(\d\d)-(\d\d\d\d)/(\d\d)?:?(\d\d)?/@', $input, $matches);

As far as regexps go, that should match a string that has no time field.

+2  A: 

Use the question mark operator and a non-capturing group to make stuff optional.

@/(\d\d)-(\d\d)-(\d\d\d\d)/(?:(\d\d):(\d\d))?/@

I'm not sure how this interacts with the match array - if having the empty array elements is absolutely critical, you might need to instead go for

@/(\d\d)-(\d\d)-(\d\d\d\d)/((?:\d\d)?):?((?:\d\d)?)/@

Which has its own false-positives (the colon in the time is now optional).

Anon.
Spot on! The second regex worked perfectly.
Camsoft
+1  A: 
  @/(\d\d)-(\d\d)-(\d\d\d\d)/((?:\d\d)?):?((?:\d\d)?)/@

does what you want (i.e. populates groups 4 and 5), but also accepts incomplete times like in

    /04-11-2010/12:/

don't know if this is fine with you

stereofrog
A: 

@OP, don't need messy regex.

$str="/04-11-2010/12:45/";
$s = array_filter(explode('/',$str));
$date=$s[1];
$time=$s[2];
$date_parts=explode("-",$date);
$time_parts=explode(":",$time);
if ( checkdate($date_parts[1],$date_parts[0],$date_parts[2]) ){
    print "date ok\n";
}
ghostdog74
Ok so we will use messy PHP instead?
Camsoft
don't tell me you don't understand what its doing?
ghostdog74
A: 

Use native PHP functions for this task, using regular expressions is a bit of an overkill.

PHP 5 has the date_parse function:

$string = '/04-11-2010/12:45/';
$dateArray = date_parse(str_replace('/', ' ', $string));
print_r($dateArray);

$string = '/04-11-2010//';
$dateArray = date_parse(str_replace('/', ' ', $string));
print_r($dateArray);

Output:

Array
(
    [year] => 2010
    [month] => 11
    [day] => 4
    [hour] => 12
    [minute] => 45
    [second] => 0
    [fraction] => 0
    [warning_count] => 0
    [warnings] => Array
        (
        )

    [error_count] => 0
    [errors] => Array
        (
        )

    [is_localtime] => 
)

Array
(
    [year] => 2010
    [month] => 11
    [day] => 4
    [hour] => 
    [minute] => 
    [second] => 
    [fraction] => 
    [warning_count] => 0
    [warnings] => Array
        (
        )

    [error_count] => 0
    [errors] => Array
        (
        )

    [is_localtime] => 
)

PHP 5.3 has a more flexible date_parse_from_format function that you could also use.

Rowlf
Thanks for this. But this looks more like overkill than a simple regular expression. In the end a good regex is going to be more robust and felxible.
Camsoft