Home > Blockchain >  Loop through preg_match_all result
Loop through preg_match_all result

Time:12-25

I am trying to loop through the result of preg_match_all() and to replace the matches.

What I am trying to achieve is to extract all the occurrences in a text that is in between curly brackets with a dollar sign in front, and then create a <span> with an id that is the content within the curly brackets.

So in the example below from the text "Working from ${spa_open_time} to ${spa_close_time} every day", I should extract ${spa_open_time} and ${spa_close_time} and replace them in the text with a <span>.

The expected result

Working from <span id="tag_spa_open_time">${spa_open_time}</span> to <span id="tag_spa_close_time">${spa_close_time}</span> every day

Here is the code I came up with so far

$text = 'Working from ${spa_open_time} to ${spa_close_time} every day';
$result = preg_match_all('/(\$\{\w \})/', $text, $positive_catch);
if ($result > 0) {
    foreach ($positive_catch as $catch) {
        if (is_array($catch)) {
            foreach ($catch as $key => $ivalue) {
                $fvalue = str_replace("\${", "", $ivalue);
                $fvalue = str_replace("}", "", $fvalue);
                $replace = '<span id="tag_'.$fvalue.'">'.$ivalue.'</span>';
                $str = str_replace($catch,$replace,$text);
            }
        }
    }
} else {
    $str = $text;
    }
echo $str;

And the current result is

Working from <span id="tag_spa_close_time"><span id="tag_spa_close_time">${spa_close_time}</span></span> to <span id="tag_spa_close_time">${spa_close_time}</span> every day

I am doing something wrong but I cannot figure out what's the problem. Here is the code in action http://sandbox.onlinephpfunctions.com/code/31894399fd981fb791c587fa04c68581c4945b6d

CodePudding user response:

I've modified your regexp to return the strings to search for (e.g. "${spa_open_time}") and the "keys" (e.g. "spa_open_time"). I'm then looping through those arrays concurrently, and generating a pair of search-and-replace strings which I'm applying to $str, which gets modified every time. At the end of the loop, $str contains your results.

$str = $text = 'Working from ${spa_open_time} to ${spa_close_time} every day';
$result = preg_match_all('/\$\{(\w )\}/', $text, $positive_catch);

if ($result > 0) {
    for ( $i=0; $i < sizeof($positive_catch[0]); $i   ) {
        $search = $positive_catch[0][$i];
        $key = $positive_catch[1][$i];
        $replace = '<span id="tag_' . $key . '">' . $search . '</span>';

        $str = str_replace($search, $replace, $str);
    }
} else {
    $str = $text;
}
echo $str;

`

CodePudding user response:

If you need to make multiple replacements, using preg_replace_callback() is easier and more reliable than looping over the results of a preg_match_all() with str_replace().

$text = 'Working from ${spa_open_time} to ${spa_close_time} every day';

$text = preg_replace_callback('/(\$\{\w \})/', function($match) {

        // Removing the leading and trailing characters for class name:
        $fvalue = substr($match[1], 2, -1);

        // Returning the match (your $ivalue) wrapped in a span-tag:
        return '<span id="tag_'.$fvalue.'">' . $match[1] . '</span>';
}, $text);

This returns the result you expect. If there are no matches, the $text string remains as-is.

Here preg_replace_callback both matches all instances of your regular expression, and lets you transform the matches and return them "in-place", without having to separately search/replace over your string. Then, any replacements will happen exactly where they should, which isn't a given with more complex string replacement operations.

CodePudding user response:

You can use a capture group \${(\w )}/ around the word characters, which will be returned as the second item of the matches array when using preg_replace_callback.

The full match is the first item in the matches.

Note that you don't have to escape the curly's in the pattern.

$text = 'Working from ${spa_open_time} to ${spa_close_time} every day';
$text = preg_replace_callback('/\${(\w )}/', function($matches) {
    return sprintf('<span id="tag_%s">%s</span>',$matches[1], $matches[0]);
}, $text);

echo $text;

Output

Working from <span id="tag_spa_open_time">${spa_open_time}</span> to <span id="tag_spa_close_time">${spa_close_time}</span> every day

See a PHP demo.

  • Related