douglas
douglas

Reputation: 137

Match Expression Results to Variable

How do I match a pattern string with group of variables defined by {{VARIABLE}} from a string that contains the {{VARIABLE}} to an array?

Example:

I have the Pattern String:

$pattern = "Image_{{DATE}}.{{EXTENSION}}";

And I would like to pass the match string

$string = "Image_2016-05-26.png";

And after passing both strings to the function, return

$result = [
    "DATE": "2016-05-26",
    "EXTENSION": "png"
];

This includes, but not limited to the example variable:

$pattern = "Image_{{YEAR}}-{{MONTH}}-{{DAY}}.{{EXTENSION}}";
$string = "Image_2016-05-26.png";
// ------------------------------
$result = [
    "YEAR" => "2016",
    "MONTH" => "05",
    "DAY" => "26",
    "EXTENSION" => ".png"
];

(Optional, I think this is the hardest) But also only return values if they're found:

$pattern = "Image_{{DATE}}.{{EXTENSION}}";
$string = "Image_2016-05-26";
// ------------------------------
$result = [
    "DATE" => "2016-05-26",
];

Is there any way to build a function passing pattern and string as variables and achieve result?

Thanks!

Upvotes: 1

Views: 45

Answers (2)

Steven Doggart
Steven Doggart

Reputation: 43743

Here's the overview of the steps you would need to do:

First, escape all of the characters which have special meaning to regex, except for the {{ and the }}. Next, replace all instances of {{ with (?P<. Next, replace all instances of }} with >.*?). Then add the prefix of /^ and the suffix of $/ to the string.

That would convert the following pattern:

Image_{{DATE}}.{{EXTENSION}}

Into the following regex pattern:

/^Image_(?P<DATE>.*?)\.(?P<EXTENSION>.*?)$/

Now, use that regex pattern to search for a match. Then loop through all the captured groups in the match and output the name/value pair for each one.

For instance, something like this will work for those examples:

function func_name($pattern, $string) {
    $pattern = "/^" . str_replace([".", "{{", "}}"], ["\.", "(?P<", ">.*?)"], $pattern) . "$/";
    preg_match($pattern, $string, $result);
    return array_filter($result, "is_string", ARRAY_FILTER_USE_KEY);
}

Of course, all of this would be much easier if your input pattern was a proper regex pattern to begin with...

As far as making the extension variable optional, you can make a capturing group optional by adding a ? after it, but there is no automated way of doing it according to your example because in your example, the . before the extension is also optional, but there is no indication in the input pattern that that is the case. In other words, you would need to convert it to /^Image_(?P<DATE>.*?)(?:\.(?P<EXTENSION>.*?))?$/, but there's no way of knowing, based only on that input pattern, that you would need to add the (?: ... )? optional group around the extension and the preceding period.

Upvotes: 1

Eugene
Eugene

Reputation: 313

use php strrt function

function func_name ($pattern, $params) {
    $toReplace = [];
    $res = array_walk($params, function($v, $k) use (&$toReplace) {
        $toReplace['{{' . $k . '}}'] = $v;
    });
    return strtr($pattern, $toReplace);
}

$params = [
    "YEAR" => "2016",
    "MONTH" => "05",
    "DAY" => "26",
    "EXTENSION" => "png"
];

$pattern = "Image_{{YEAR}}-{{MONTH}}-{{DAY}}.{{EXTENSION}}";

echo func_name($pattern, $params); // Image_2016-05-26.png

Upvotes: 0

Related Questions