Как я могу заменить несколько строк в строке без перекрытия результатов?

Я пытаюсь создать общие маски из строки, например:

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

заменить:

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

вместо этого я продолжаю перекрывать замены и получаю что-то вроде этого (используя цикл str_replaceС):

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

потому что st находится в уже замененном {start} и dd находится в {middle}.

как бы вы заменить?

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

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

3 ответов


Я могу неправильно понять, но вам, похоже, не нужно регулярное выражение для замены. Это простая, буквальная замена.

$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() это круто. Он принимает очень читаемый ввод, и он не заменяет, как ваша проблема в цикле.


можно использовать preg_replace такой:

$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

ядро этого регулярного выражения-это отрицательный lookaead:(?![^{}]*})

которые избегают совпадающих ключей массива, если он заключен в {...} так как все замены заключены в {...}.


поиск строки для каждой замены. Если он найдет его, он разделит строку и будет искать оставшуюся часть строки для любых других замен.

$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

он будет искать и находить их в указанном Вами порядке.