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.