1

Using the below I can match all the items in an array but I can only replace the matched values which is expected. Is there a way do do the same but instead of a straight replace, wrap the matched text with specified values?

Current Code:

$colours = array("Red", "Blue", "Green");
$string = "There are three Red and Green walls.";

echo str_replace($colours, "?", $string);

Current Ouput

There are three ? and ? walls.

Wanted Ouput

There are three %1%Red%2% and %1%Green%2% walls.
2
  • If you want a primitive solution - then supply an array for the replacements as well, with the words wrapped in %1%…%2% each. Commented Apr 7, 2021 at 12:21
  • 1
    Do you mean preg_replace("/\b(?:" . implode('|', $colours) . ")\b/", '%1%$0%2%', $string)? 3v4l.org/9077N Commented Apr 7, 2021 at 12:21

4 Answers 4

1

Depending on whether you want to account for context or not, the solutions will vary.

If you plan to just match the strings as is in any context and repalce with their copies enclosed with %1% and %2%, you need to use

preg_replace("/" . implode("|", array_map(function($i) {return preg_quote($i, "/");}, $colours)) . "/", '%1%$0%2%', $string)

The regex is formed here using | OR operator and all special chars in the items in the $colours array are escaped with \ using preg_quote function. The $0 in the replacement refers to the whole match value.

If $colours are phrases with whitespaces, you would need to sort the items so that the longer strings come first:

rsort($colours, SORT_FLAG_CASE | SORT_STRING);
echo "\n" . preg_replace("/" . implode("|", array_map(function($i) {return preg_quote($i, "/");}, $colours)) . "/", '%1%$0%2%',$string);

If these $colours are simple English letter words, and you want to match them as whole words, you do not need preg_quote and you can use word boundaries, like:

preg_replace("/\b(?:" . implode('|', $colours) . ")\b/", '%1%$0%2%', $string)

To make the search case-insensitive, add i flag after last / regex delimiter in the preg_replace first argument.

See the PHP demo:

$colours = array("Red", "Blue", "Green");
$string = "There are three Red and Green walls.";

echo preg_replace("/" . implode("|", array_map(function($i) {return preg_quote($i, "/");}, $colours)) . "/", '%1%$0%2%', $string);
// => There are three %1%Red%2% and %1%Green%2% walls.

echo "\n" . preg_replace("/\b(?:" . implode('|', $colours) . ")\b/", '%1%$0%2%', $string);
// => There are three %1%Red%2% and %1%Green%2% walls.

$colours = array("Red", "Blue", "Green", "Blue jeans");
$string = "There are three Red and Green walls and Blue jeans.";
rsort($colours, SORT_FLAG_CASE | SORT_STRING);

echo "\n" . preg_replace("/" . implode("|", array_map(function($i) {return preg_quote($i, "/");}, $colours)) . "/", '%1%$0%2%',$string);
// => There are three %1%Red%2% and %1%Green%2% walls and %1%Blue jeans%2%.
Sign up to request clarification or add additional context in comments.

3 Comments

Is it possible to make this a case insensitive check without affecting the out the wrapped strings?
I've used this and it seems to do it, does it make sense "/\b(?i:" . implode('|', $colours) . ")\b/"
@llanato If all you need is to find the terms case insensitively, and wrap the matches found, just add i flag, "/\b(?:" . implode('|', $colours) . ")\b/i"
0

i think you could do with array_map. Here is my example :

$colours = array("Red", "Blue", "Green");

$string = "There are three Red and Green walls.";

$func = function($value) use ($colours){

return in_array($value, $colours) ? "%1%". $value ."%2%" : $value;

};

$text = array_map($func, explode(" ", $string));

$text = implode(" ", $text);

echo $text; `

Comments

0

What you want is preg_replace. You will be able to replace the matches with a string that includes the match. In this case "%1%$0%2%" where $0 will be replaced with the match.

However, you will need to quote (with preg_quote) and add delimiters to the members of your array. We can do that with array_map.

This is the code:

echo preg_replace
(
    array_map
    (
        function($input)
        {
            return "/".preg_quote($input, "/")."/";
        },
        $colours
    ),
    "%1%$0%2%",
    $string
);

No, I do not suggest to assume they are safe to use without quoting, even if in this case they are. Yes, creating a single regex pattern with them is viable, but why bother?

Comments

0

simplest but not most effective:

$colours = array("Red", "Blue", "Green");
$colours_replacment = array('%1%Red%2%', '%1%Blue%2%', '%1%Green%2%');
$string = "There are three Red and Green walls.";

echo str_replace($colours, $colours_replacment, $string);

simple and more effective:

$colours = array("Red", "Blue", "Green");
$string = "There are three Red and Green walls.";

foreach($colours as $colour) {
    $string = str_replace($colour, '%1%' . $colour . '%2%', $string);
}

echo $string;

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.