PHP: проблема с str_replace - PullRequest
       16

PHP: проблема с str_replace

1 голос
/ 13 марта 2011

Я заметил странное поведение функции str_replace . Можете ли вы сказать мне, почему вместо номера 3 в no_2 я получаю no_4 ?

Вот случай:

$pattern = array(1,2,3);
$change = array(1,3,4); 
$sql = "SELECT * FROM %s WHERE no_1 IN (%s) AND no_2 IN (%s) AND no_3 IN (%s)";

$test_multiply[] = str_replace($pattern, $change, $sql);

Что дает:

Array ( [0] => SELECT * FROM %s WHERE no_1 IN (%s) AND no_4 IN (%s) AND no_4 IN (%s) ) 

Можете ли вы сказать мне, что я должен сделать, чтобы получить no_3 вместо no_2?

Ответы [ 4 ]

7 голосов
/ 13 марта 2011

Документация для str_replace() говорит (цитирование) :

Потому что str_replace () заменяет слева направо, может заменить ранее вставленное значение при выполнении нескольких замен.

Я полагаю, что вы именно в этой ситуации:

  • Ваш no_2 получаетзаменен на no_3 - из-за второго элемента в ваших $pattern и $change массивах
  • Но, затем, no_3 заменяется на no_4 -из-за элементов thid в ваших массивах $pattern и $change


Чтобы избежать этой конкретной ситуации, вы можете попробовать изменить порядок элементов в этихдва массива:

$pattern = array(3, 2, 1);
$change = array(4, 3, 1); 

И вы получите следующий результат:

SELECT * FROM %s WHERE no_1 IN (%s) AND no_3 IN (%s) AND no_4 IN (%s)
3 голосов
/ 13 марта 2011

Если вы используете str_replace с набором игл, каждая игла заменяется отдельным вызовом str_replace.Вы можете себе представить, что что-то подобное происходит внутри:

for ($i=0, $n=min(count($pattern),count($change)); $i<$n; $i++) {
    $sql = str_replace($pattern[$i], $change[$i], $sql);
}

Итак, на первой итерации все 1 заменяются на 1, затем все 2 заменяются на 3, а затем все3 заменяется на 4:

  1. SELECT * FROM %s WHERE no_1 IN (%s) AND no_2 IN (%s) AND no_3 IN (%s)
  2. SELECT * FROM %s WHERE no_1 IN (%s) AND no_3 IN (%s) AND no_3 IN (%s)
  3. SELECT * FROM %s WHERE no_1 IN (%s) AND no_4 IN (%s) AND no_4 IN (%s)

Ксделать одновременную замену, вы можете использовать preg_replace_callback и вызывать функцию сопоставления для каждого сопоставленного шаблона:

function str_replacep(array $search, array $replace, $subject, &$count=0) {
    $combinedPattern = '/(?:'.implode('|', array_map(function($str) { return preg_quote($str, '/'); }, $search)).')/';
    $map = array_combine($search, $replace);
    $mapping = function($match) use ($map, $count) {
        $count++;
        return $map[$match[0]];
    };
    return preg_replace_callback($combinedPattern, $mapping, $subject);
}

Я использовал анонимную функцию в этом примере, ноон также будет работать с create_function.

При этом порядок замены не имеет значения.Вы даже можете обменять два значения:

var_dump(str_replacep(array(1,2), array(2,1), "12"));  // string(2) "21"
1 голос
/ 13 марта 2011

Сначала вы заменяете 1 на 1, так что все в порядке

SELECT * FROM %s WHERE no_1 IN (%s) AND no_2 IN (%s) AND no_3 IN (%s)

Затем, заменяя 2 на 3, вы получаете

SELECT * FROM %s WHERE no_1 IN (%s) AND no_3 IN (%s) AND no_3 IN (%s)

Затем замена 3 на 4, в результате чего SELECT * FROM %s WHERE no_1 IN (%s) AND no_4 IN (%s) AND no_4 IN (%s)

Возможно, вам следует заменить 2 другим значением (не 3), которое вы можете заменить позже.

0 голосов
/ 13 марта 2011

Потому что как только вы замените 2 на 3, следующая замена всегда заменит 3 на 4

...