Избегайте замены заполнителя в строке замены

скажем, у меня есть эта строка:

"my string ? other string ?"
  • Я хочу заменить первый "?" с "first param ?" (обратите внимание на заполнитель ? внутри текста)
  • и второй "second param".

ЕСЛИ я делаю preg_replace, я получаю это:

my string first param second param other string ?
          ^^^^^^^^^^^^^^^^^^^^^^^^              ^
                WRONG                    NOT REPLACED

По сути, поскольку первая замена также имеет заполнитель, preg_replace достаточно глупо заменить этот заполнитель вместо реального второго в конце.

Код с preg_replace:

$search = ["?", "?"];
$params = ["first param ?", "second param"];
$query  = "first text ? other text ?";

//> Marker in the query are ?, so I create the array to preg_replace
$search = array_fill(0,count($params),'/\?/');
$query = preg_replace(
    $search,                // a list of ?
    $params,                // escaped values
    $query,                 // from query
    1                       // replace only 1 time
);
//output: first text first param second param other text ?

Любой намек на то, как избежать поиска заполнителя внутри замены?

Живой код с preg_replace: http://sandbox.onlinephpfunctions.com/code/e705ba454d030103344bc826e0fe0bf42d5b7b90

Не работает также с str_replace

$search = ["?", "?"];
$params = ["first param ?", "second param"];
$query  = "first text ? other text ?";

$query = str_replace ($search, $params, $query);
echo $query;

// output: first text first param second param other text first param second param

Живой код с str_replace: http://sandbox.onlinephpfunctions.com/code/dc259325411ee42de759f145eac78b339f329f74

Исключенный вывод

Дано:

$search = ["?", "?"];
$params = ["first param ?", "second param"];
$query  = "first text ? other text ?";

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

first text first param ? other text second param
           ^^^^^^^^^^^^^            ^^^^^^^^^^^^
         first placeholder         second placeholder

Исключенный вывод с 3 параметрами

$search = ["?", "?", "?"];
$params = ["first param", "second param ?", "third param"];
$query  = "first text ? other text ? other chunk ?";

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

first text first param other text  second param ? other chunk third param
           ^^^^^^^^^^^^^            ^^^^^^^^^^^^              ^^^^^^^^^
         first placeholder         second placeholder         third placeholder

Мое индивидуальное решение

Я придумал возможное решение, используя preg_split, но, честно говоря, это настолько хакерски, что должно быть что-то лучше:

 $parts = preg_split('/(\?)/', $query, -1, PREG_SPLIT_DELIM_CAPTURE);

 foreach($parts as $k=>&$v) {
        // if is odd, then it's a placeholder
        if ($k%2 == 1)
            $v = $params[$k/2];  // replace placeholder with a param
 }

 $query = implode('',$parts);

Что если убрать ограничение , 1?

The fourth bird 22.06.2019 10:29

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

giò 22.06.2019 10:34

вы хотите использовать str_replace()? см. демо для этого 3v4l.org/t4QKq

Always Sunny 22.06.2019 10:35

Пробовал с str_replace, и это не работает, потому что несколько раз заменяет один и тот же заполнитель: sandbox.onlinephpfunctions.com/code/…

giò 22.06.2019 10:37

каков ваш ожидаемый результат в данном примере с песочницей?

Always Sunny 22.06.2019 10:40

@AlwaysSunny: я добавил ожидаемый результат в конце своего поста

giò 22.06.2019 10:43

извините за вопрос, но вы пытаетесь создать что-то для mySql

Tito 22.06.2019 10:51

Тито: нет, похоже, но не sql

giò 22.06.2019 10:58

Ко всем: пока мы разговаривали, я добавил свое возможное решение (найдите его ниже), оно использует preg_split, но, честно говоря, это что-то очень плохое

giò 22.06.2019 11:01
Стоит ли изучать 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
9
1 444
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Это будет работать только для 2 заполнителей.

$search = [
    "/^([^?]*)\?/",     # matches everything that is not a question mark in group 1, then a question mark
    "/^(.*)\?/"         # matches everything until last question mark in group 1, then a question mark
];
$params = ["$1first param ?", "$1second param"];

$query = "first text ? other text ?";

$query = preg_replace($search, $params, $query);

echo $query;

Выход:

first text first param ? other text second param

Тото +1, но этот материал динамический, я не знаю, сколько $search прибудет в эту функцию. Он должен быть общим

giò 22.06.2019 10:50

@giò: Не могли бы вы привести примеры и ожидаемый результат для 3 или более заполнителей? с участием

Toto 22.06.2019 10:51

Пытаться:

$s = "my string ? other string ?";
$s = preg_replace('/\?/', "first ?", $s, 1);
$s = preg_replace('/((?:^.*?\?)?.*?)\?/', "$1second text", $s);
echo $s;

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

Ответ принят как подходящий

Любая пользовательская логика замены должна быть реализована с помощью preg_replace_callback, например:

$params = ["first param", "second param ?", "third param"];
$query  = "first text ? other text ? other chunk ?";

echo preg_replace_callback('/\?/', function($m) use (&$params) {
    return array_shift($params);
}, $query);

Текущий код: http://sandbox.onlinephpfunctions.com/code/33f4804b49103e54e8070e8d9959ec9642930857

Хорошо, позвольте мне создать живой фрагмент, готово. Очень приятно, хотя это не «пользовательская» логика replacemnet, это просто очень простая последовательная замена заполнителя :)

giò 22.06.2019 11:02

Я только что обновил свой ответ тем же. Вы поняли мою точку зрения.

Toto 22.06.2019 11:08

Это можно сделать с помощью цикла while() с проверкой strpos(), но также explode() является еще одним решением этой проблемы:

$params = ['first param ?', 'second param'];
$query = 'my string ? other string ?';
$str = '';

foreach(explode('?', $query, count($params) + 1) as $token) {
    $str .= $token . array_shift($params);
}

echo $str;

См. живая демонстрация здесь

да +1, взрыв похож на preg_slit, альт, посмотрев фрагмент, я думаю, что принятый ответ - самое простое решение

giò 22.06.2019 12:13

Да, но разница в том, что в explode() нет слоя PCRE, как это происходит в preg_split() или других preg_* функциях. Поэтому он должен работать быстрее.

revo 22.06.2019 12:15

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