Выражение регулярного выражения для замены слова между двумя разными словами в строке

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

Например, учитывая следующую строку:

Lorem ABC ipsum ABC bla MNO bla ipsum ABC asfg 123 hello ABC dd ABC XYZ hello ABC

Ожидаемый результат будет следующим:

Lorem ABC ipsum ABC bla MNO bla ipsum asfg 123 hello dd XYZ hello ABC

Таким образом, заменены только ABC три между MNO и XYZ.

Я попробовал несколько регулярных выражений внутри preg_replace в PHP, но безуспешно.

Например, в этом я не знаю, как не сопоставить все, кроме ABC:

/(?<=MNO)(.*)ABC(.*)(?=XYZ)/g

Вот тестовая ссылка.

Я был бы признателен за использование регулярных выражений и preg_replace в этом случае.

Любые идеи? Спасибо

Обязательно ли использовать preg_replace или можно использовать и preg_replace_callback?

Wiktor Stribiżew 24.02.2019 12:02

Виктор, к preg_replace_callback можно привыкнуть.

alcoceba 24.02.2019 12:07

Могут ли MNO и XYZ встречаться более одного раза?

Rarst 24.02.2019 12:07

Виктор, добавил к вопросу один пример, который может пролить свет на него.

alcoceba 24.02.2019 12:14

Редко, в данном случае только один раз, но я не против

alcoceba 24.02.2019 12:15
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
2
5
86
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Это сработает, если в предложении есть только одно вхождение MNO и XYZ.

Попробуйте это регулярное выражение:

ABC(?!.*MNO)(?=.*XYZ)

Замените каждое совпадение пустой строкой

Нажмите для демонстрации

Объяснение:

  • ABC - соответствует ABC
  • (?!.*MNO) - отрицательный просмотр вперед, чтобы убедиться, что за текущим совпадением не следует MNO где-то позже в строке
  • (?=.*XYZ) - положительный просмотр вперед, чтобы убедиться, что за текущим совпадением следует XYZ где-то позже в строке

Код(РЕЗУЛЬТАТ)

$re = '/ABC(?!.*MNO)(?=.*XYZ)/m';
$str = 'Lorem `ABC` ipsum ABC bla MNO bla ipsum ABC asfg 123 hello ABC dd ABC XYZ hello ABC
';
$subst = '';
$result = preg_replace($re, $subst, $str);
echo "The result of the substitution is ".$result;

Работает идеально, это как раз то, что мне нужно.

alcoceba 24.02.2019 12:27

megatxi Я чувствую, что решение, предоставленное @WiktorStribiżew, намного лучше и должно быть принято в качестве решения.

Gurmanjot Singh 24.02.2019 12:30
Ответ принят как подходящий

Вы можете использовать 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 в конце регулярного выражения также необходим, чтобы . соответствовал символам разрыва строки.

Во втором примере (?<=MNO) — это положительный просмотр назад, который не использует текст и требует, чтобы MNO присутствовал непосредственно слева от текущего местоположения, а (?=XYZ) — это положительный просмотр, который требует, чтобы XYZ присутствовал сразу же справа от текущего местоположения. и не потребляет текст, поэтому здесь нет необходимости в группах.

С preg_replace намного сложнее:

preg_replace('~(?:\G(?!\A)|MNO)(?:(?!MNO).)*?\KABC(?=(?:(?!MNO).)*?XYZ)~s', 'XXX', $s)

См. демонстрация регулярных выражений.

Подробности

  • (?:\G(?!\A)|MNO) - конец предыдущего матча или MNO
  • (?:(?!MNO).)*? - любой 1 символ, 0 или более вхождений, как можно меньше, которые не начинают последовательность MNO символов
  • \K - оператор сброса совпадения, который отбрасывает текст в буфере совпадения
  • ABC - ABC
  • (?=(?:(?!MNO).)*?XYZ) - сразу справа должно быть 0+ символов, как можно меньше, которые не начинают последовательность символов MNO, за которой следует XYZ.

В этом случае он работает с более чем одним вхождением MNO и XZY. Пока не нужно, но при необходимости буду иметь в виду. Большое спасибо.

alcoceba 24.02.2019 12:30

Другие вопросы по теме