If you need to do straightforward string replacement that doesn't reiterate the result string multiple times you should use strtr()
instead:
strtr($string, array(
'imprint' => 'print',
'print' => 'imprint',
'paper' => 'machine',
));
The words to replace are ordered by string length, the most specific first.
Note: this is of course not as flexible as regular expressions, especially when it comes to replacing only full words, i.e. /\bword\b/
will match word
only if it stands by itself; this is not something you can do with strtr()
and friends.
Using regular expressions
To make preg_replace()
perform only a single pass over the string, you need to combine your replacement keys together into a single expression, i.e.
/imprint|print|paper/
This expression uses alternation, effected by the pipe character in between the search strings. To match only whole words you will need to add boundary matches, a special \b
sequence that matches the transition between words and non-words.
/\b(?:imprint|print|paper)\b/
This will match "imprint"
but not "pimprint"
.
If you're going down this route, performing the replacement needs to be done using preg_replace_callback()
; for each match it finds a custom function gets executed in which you can determine what to replace it with. You would need to create a replacement map for it, much like the one I've used for my earlier strtr()
example.
$map = array(
'imprint' => 'print',
'print' => 'imprint',
'paper' => 'machine',
);
$replacer = function($match) use ($map) {
// $match[0] holds the found word
return $map[$match[0]];
};
preg_replace_callback('/\b(?:imprint|print|paper)\b/', $string, $replacer);
Making it dynamic
I've created the regular expression by hand, but to make this flexible you need to generate this dynamically, based off the replacement map. To do this, we need to:
- Extract the keys from the replacement map;
- Escape any special characters;
- Build the final expression.
This is how you would build the expression:
// step 1
$replacement_keys = array_keys($map);
// step 2
$escaped_keys = array_map(function($key) {
return preg_quote($key, '/');
}, $replacement_keys);
// step 3
$pattern = '/\b(?:' . join('|', $escaped_keys) . ')\b/';