Вы можете использовать preg_replace_callback
:
$s = preg_replace_callback('~(MNO)(.*?)(XYZ)~s', function($m) {
return $m[1] . str_replace('ABC', 'XXX', $m[2]) . $m[3];
}, $s);
Или, с осторожностью, сделать код внутри анонимной функции немного более простым:
$s = preg_replace_callback('~(?<=MNO).*?(?=XYZ)~s', function($m) {
return str_replace('ABC', 'XXX', $m[0]);
}, $s);
См. Демонстрация PHP
Здесь (MNO)(.*?)(XYZ)
соответствует и захватывает MNO
, все между MNO
и XYZ
, а затем XYZ
в три группы и внутри анонимной функции, все ABC
s заменяются только во второй группе.Обратите внимание, что флаг s
в конце регулярного выражения также необходим для того, чтобы .
соответствовал символам разрыва строки.
Во втором примере (?<=MNO)
является положительным взглядом сзади, который не потребляет текст,и требует, чтобы MNO
присутствовал непосредственно слева от текущего местоположения, а (?=XYZ)
является положительным прогнозом, который требует, чтобы XYZ
присутствовал немедленно справа от текущего местоположения, и также не потребляет текст, таким образом,здесь нет необходимости в группах.
С preg_replace
:
preg_replace('~(?:\G(?!\A)|MNO)(?:(?!MNO).)*?\KABC(?=(?:(?!MNO).)*?XYZ)~s', 'XXX', $s)
гораздо сложнее. См. демонстрационную версию regex .
Подробности
(?:\G(?!\A)|MNO)
- конец предыдущего матча или MNO
(?:(?!MNO).)*?
- любой 1 символ, 0 или более вхождений, как можно меньше, который не запускает MNO
последовательность символов \K
- оператор сброса совпадений, который сбрасывает текст в буфере совпадений ABC
- ABC
(?=(?:(?!MNO).)*?XYZ)
- сразу направо, должно быть 0+ символов, как можно меньше, которые не запускаютсяпоследовательность символов MNO
, за которой следует XYZ
.