Заменить каждый экземпляр между двумя символами
У меня есть следующие данные ниже, где {n}
представляет местозаполнитель.
{n}{n}A{n}{n}A{n}
{n}A{n}{n}{n}{n}A
{n}{n}A{n}A{n}{n}
{n}{n}{n}A{n}A{n}B
{n}A{n}{n}B{n}{n}
A{n}B{n}{n}{n}{n}
Я хотел бы заменить каждый экземпляр заполнителя между двумя символами А, например, буквой C
. Я написал для него следующее регулярное выражение, и я использую функцию preg_replace
.
$str = preg_replace('~(?<=A)(\{n\})*(?=A)~', 'C', $str);
Проблема заключается в том, что он заменяет все экземпляры между двумя A одним C
. Как я могу исправить свое регулярное выражение или вызов preg_replace
для замены каждого отдельного экземпляра заполнителей на C
?
Это должен быть мой вывод.
{n}{n}ACCA{n}
{n}ACCCCA
{n}{n}ACA{n}{n}
{n}{n}{n}ACA{n}B
{n}A{n}{n}B{n}{n}
A{n}B{n}{n}{n}{n}
Но в настоящее время он выводит это.
{n}{n}ACA{n}
{n}ACA
{n}{n}ACA{n}{n}
{n}{n}{n}ACA{n}B
{n}A{n}{n}B{n}{n}
A{n}B{n}{n}{n}{n}
Ответы
Ответ 1
Вы можете решить проблему, привязавшись к \G
.
$str = preg_replace('~(?:\G(?!\A)|({n})*A(?=(?1)++A))\K{n}~', 'C', $str);
Функция \G
- это привязка, которая может совпадать в одной из двух позиций; начало позиции строки или положение в конце последнего совпадения. Управляющая последовательность \K
сбрасывает исходную точку сообщенного соответствия, и все ранее использованные символы больше не включаются.
Чтобы уменьшить количество обратных следов, вы можете использовать более сложное выражение:
$str = preg_replace('~\G(?!\A)(?:{n}
|A(?:[^A]*A)+?((?=(?:{n})++A)\K{n}
|(*COMMIT)(*F)))
|[^A]*A(?:[^A]*A)*?(?1)~x', 'C', $str);
Ответ 2
Несколько более подробное, но более простое решение - использовать начальное выражение, чтобы разбить текст на группы; затем примените индивидуальное преобразование внутри каждой группы:
$text = preg_replace_callback('~(?<=A)(?:\{n\})*(?=A)~', function($match) {
// simple replacement inside
return str_replace('{n}', 'C', $match[0]);
}, $text);
Я сделал небольшую настройку для выражения, чтобы избавиться от захвата памяти, что необязательно, используя (?:...)
.
Ответ 3
(?<=A){n}(?=(?:{n})*A)|\G(?!^){n}
Вы можете попробовать это. Заменить на C
. Здесь вы должны использовать \G
для утверждения позиции в конце предыдущего совпадения или начала строки для первого совпадения.
Итак, вы можете совпадение после первого матча. См. Демонстрацию.
https://regex101.com/r/wU4xK1/7
Здесь сначала вы сопоставляете {n}
, у которого A
позади него и A
после него, у которого может быть {n}
между ними. После захвата вы используете \G
до reset до конца предыдущего совпадения и впоследствии сохраняете замену найденного {n}
.
$re = "/(?<=A){n}(?=(?:{n})*A)|\\G(?!^){n}/";
$str = "{n}{n}A{n}{n}A{n}\n{n}A{n}{n}{n}{n}A\n{n}{n}A{n}A{n}{n}\n{n}{n}{n}A{n}A{n}B\n{n}A{n}{n}B{n}{n}\nA{n}B{n}{n}{n}{n}";
$subst = "C";
$result = preg_replace($re, $subst, $str);