如何在不重叠结果的情况下替换字符串中的多个字符串?

I'm trying to create common masks from a string like so:

012abc.d+e_fg~hijk => 012{start}.d+{middle}_fg~{end}jk

replace:

$arrFromTo = array(
              'st' => '{pre}',
              'abc' => '{start}',
              'e' => '{middle}',
              'hi' => '{end}',
              'dd' => '{post}'
             );

Instead I keep overlapping replacements and get something like this instead (using a loop of str_replace's):

012{{pre}art}.d+{mi{post}le}_fg~{end}jk

Because the st is found in the already replaced {start} and dd is found in {middle}.

How would you replace the following?

$str = 'abc.d+e_fg~hijk';

echo replace_vars($str); // Desired output: 012{start}.d+{middle}_fg~{end}kJ

I might misunderstand, but you don't seem to need regex for the replacing. They're simple, literal replacements.

$from = '012abc.d+e_fg~hijk';
$arrFromTo = array(
              'st' => '{pre}',
              'abc' => '{start}',
              'e' => '{middle}',
              'hi' => '{end}',
              'dd' => '{post}'
             );
$to = strtr($from, $arrFromTo); // 012{start}.d+{middle}_fg~{end}jk

strtr() is awesome. It takes a very readable input and it doesn't re-replace like your problem in the loop.

You can use preg_replace like this:

$str = '012abc.d+e_fg~hijk';
$arrFromTo = array(
              'st' => '{pre}',
              'abc' => '{start}',
              'e' => '{middle}',
              'hi' => '{end}',
              'dd' => '{post}'
             );

$reArr=array();
foreach($arrFromTo as $k=>$v){
   $reArr['/' . $k . '(?![^{}]*})/'] = $v;
}

echo preg_replace(array_keys($reArr), array_values($reArr), $str);
//=> 012{start}.d+{middle}_fg~{end}jk

Core of this regex is this negative lookaead: (?![^{}]*})

Which avoid matching keys of array if it is enclosed in {...} since all the replacements are enclosed in {...}.

This will search the string for each replacement in order. If it finds one, it will split the string, and search the remainder of the string for any other replacements.

$str = '012abc.d+e_fg~hijk';

$rep = array(
    'st' => '{pre}',
    'abc' => '{start}',
    'e' => '{middle}',
    'hi' => '{end}',
    'dd' => '{post}'
);

$searched = '';

foreach ($rep as $key => $r) {
    if (strpos($str, $key) !== false) {

        $searched .= substr($str, 0, strpos($str, $key)) . $r;
        $str = substr($str, strpos($str, $key) + strlen($key));

    }
}

$searched .= $str;

echo $searched; //012{start}.d+{middle}_fg~{end}jk

It will search and find them in the order that you have specified.