0

I have a string $src with two variable placeholders %%itemA%% and %%itemB%%. The idea is for the regular expression to match any term listed ITEMA|ITEMB|ITEMC, case insensitively, and replace the term with the value of the array item using the term as the array key.

$replacements = [
    'itemA' => 'replacedItemA',
    'itemB' => 'replacedItemB',
    'itemC' => 'replacedItemC'
];

$src = "A B C %%itemA%% D E F %%itemB%% G H I";

$src = preg_replace('/\%\%(ITEMA|ITEMB|ITEMC)%%/i', $replacements['\1'], $src);

echo $src;

In this example the expected result is for %%itemA%% to be replaced with $replacements['itemA']'s value and %%itemB%% to be replaced with $replacements['itemB']'s value

Expected output from the echo was

A B C replacedItemA D E F replacedItemB G H I

Actual output, oddly, simply replaced the found terms with nothing (note the double spaces where the variable was removed)

A B C D E F G H I

Why is the term's string not being used in the $replacements['key'] to use the value of the array variable?

2 Answers 2

3

Your approach is wrong. Since you are dealing with literal strings, you can avoid the regex and use a faster way:

$replacements = [
    '%%itemA%%' => 'replacedItemA',
    '%%itemB%%' => 'replacedItemB',
    '%%itemC%%' => 'replacedItemC'
];

$str = strtr($str, $replacements);
Sign up to request clarification or add additional context in comments.

4 Comments

Hi, my understanding is that the regex is more efficient, as there will be a lot of strings filtered through? I'll do some benchmarking to test if I can find a solution to make my approach work too
@CraigMcArthur: "my understanding is that the regex is more efficient": it's a totally false idea!
Unless there is a need to also modify the $replacements, and specify some additional context for %%...%% strings, this can be used, too. Regex allows some more things that mere strtr does not.
The $replacements should be also modified to include delimiters to use this approach. If it is not possible, it not usable.
0

You just need to replace the preg_replace with preg_replace_callback like this:

$src = preg_replace_callback('/%%(ITEM[ABC])%%/i', function ($m) use ($replacements) {
 return isset($replacements[$m[1]]) ? $replacements[$m[1]] : $m[0];
}
, $src);

See IDEONE demo

The issue is that \1 backreference can only be used inside the pattern to refer to the text captured with the first capturing group or inside a replacement pattern, but only as a literal part of it. The \1 is not automatically evaluated to be used as an argument.

I also contracted the pattern a bit, but I guess it is just a sample.

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.