neubert neubert - 6 months ago 10
PHP Question

matching a part of a string from the beginning

I have a date (eg. yyyy-mm-dd hh:mm:ss) and I want to be able to return true if we have a string matching that pattern, completely, or that partially matches that pattern, from beginning to end. eg.

44
would match the pattern because
44
would match the yy but
-12
would not match because
-
isn't a valid "y" character.

A few inelegant solutions occur to me. I could do
preg_match
on something like this:

#^\d(\d(\d(\d(-)?)?)?)?$#


That just performs a partial match based on the year. It'd need to be expanded out to account for the month, day, hour, minute, etc, but that should show idea # 1.

I could also do something like...

$patterns = [
'',
'\d',
'\d\d',
'\d\d\d',
'\d\d\d\d',
'\d\d\d\d-',
...
];
isset($patterns[strlen($str)] && preg_match('#^' . $patterns[strlen($str)] . '$#', $str)


But that kinda seems convoluted as well.

I could also do this:

switch (strlen($str)) {
case 1: return preg_match('#^\d$#', $str);
case 2: return preg_match('#^\d\d$#', $str);
case 3: return preg_match('#^\d\d\d$#', $str);
case 4: return preg_match('#^\d\d\d\d$#', $str);
case 5: return preg_match('#^\d\d\d\d-$#', $str);
...
}


But that seems bloated as well.

In other words, I'm looking for a function for which
2005-
will return true, as will
2
and
2005-1
. But
-2005
will return false, as will
205-
or
neubert
.

What I want to be able to do is to pass valid values into an SQL query. eg.
WHERE date_column LIKE '$str%'
. If
date_column
is a DATETIME then searching for
-12-
is a waste of time because it's not possible for
date_column
to have that as a value.

Any ideas?

Answer

Something like this should work:

function doesMatch($str) {
    // The date pattern split so that each array entry matches exactly one character
    $pattern_chunks = array(
        '\d', '\d', '\d', '\d', '-',
        '\d', '\d', '-',
        '\d', '\d',
        '\s',
        '\d', '\d', ':',
        '\d', '\d', ':',
        '\d', '\d'
    );

    $chunk_count = count($pattern_chunks);
    $str_len = strlen($str);

    // If the string is empty, it's clearly not a date
    if ( $str_len < 1 ) { return false; }

    // If the string is longer than our pattern chunks, there's no way it matches
    if ( $str_len > $chunk_count ) { return false; }

    // Make a pattern using the first N chunks of our pattern parts
    $pattern = '^' . implode('', array_slice($pattern_chunks, 0, $str_len)) . '$';

    // Return if the string matches
    return (preg_match($pattern, $str) > 0);
}

For example your input string is 6 characters long, it only uses the first 6 chunks of the date pattern (^\d\d\d\d-\d$).

Comments