Как заменить n-ое вхождение в строку

Мне нужно простое и быстрое решение для замены n-го вхождения (placeholder) в строке.

Например, n-ый знак вопроса в sql-запросе должен быть заменен предоставленным значением.

$subject = "SELECT uid FROM users WHERE uid = ? or username = ?";

Итак, мне нужна функция str_replace_nth($seach, $replace, $subject, $nth) а для второго вопросительного знака ее следует называть str_replace_nth("?", $username, $subject, 2);

Есть идеи?

PS Пожалуйста, не предлагайте мне использовать PDO, потому что я работаю над FDO (Facebook Data Object) библиотекой с интерфейсом, подобным PDO, но для FQL.

Важное замечание! Я понял, что этот подход плох, потому что после первой замены запрос изменяется и индексы теряются. (Плохие подходы приходят, когда вы программируете поздно ночью :() Итак, как @GolezTrol упоминает в комментарии, лучше заменить все сразу.

Вот функция, которую вы просили:

 $subject = "SELECT uid FROM users WHERE uid = ? or username = ?"; function str_replace_nth($search, $replace, $subject, $nth) { $found = preg_match_all('/'.preg_quote($search).'/', $subject, $matches, PREG_OFFSET_CAPTURE); if (false !== $found && $found > $nth) { return substr_replace($subject, $replace, $matches[0][$nth][1], strlen($search)); } return $subject; } echo str_replace_nth('?', 'username', $subject, 1); 

Примечание: $nth – индекс на основе нуля!

Но я бы рекомендовал использовать что-то вроде следующего, чтобы заменить заполнители:

 $subject = "SELECT uid FROM users WHERE uid = ? or username = ?"; $args = array('1', 'steve'); echo vsprintf(str_replace('?', '%s', $subject), $args); 

Вместо использования вопросительных знаков, почему бы не использовать такие маркеры:

 $subject = "SELECT uid FROM users WHERE uid = :uid or username = :username"; $parameters = array( ':uid' => 42, ':username' => 'John', ); $subject = str_replace(array_keys($parameters), $parameters, $subject); 

Валидация по входному параметру не выполнена

  function str_replace_nth($search, $replace, $subject, $nth){ $match_arr = explode($search,$subject); $match_arr = array_filter($match_arr); foreach($match_arr as $key=>$val){ if($key == $nth-1){ // array index start with Zero $match_arr[$key] .= $replace; }else{ $match_arr[$key] .= '?'; } } return implode('',$match_arr); } 

Ни одно из ваших решений не работало для меня, поэтому я сделал следующее:

 $sql1 = "SELECT * FROM allegro_user WHERE User_Emp_Nb = ? AND User_Activ_status = ?"; $sql2 = "SELECT * FROM allegro_user WHERE User_Emp_Nb = :emp_nb AND User_Activ_status = :activ"; function prepare_query($sql, $args) { foreach ($args as $key => $value) { if (is_numeric($key)) { $sql = preg_replace('/\?/', "'" . $value . "'", $sql, 1); } else { $sql = str_replace($key, "'" . $value . "'", $sql); } } return $sql; } tab($sql1); $sql = prepare_query($sql1, array('0216313', 'A')); tab($sql1); tab($sql2); $sql = prepare_query($sql2, array(':emp_nb' => '0216313', ':activ' => 'A')); tab($sql2); 

tab () – это просто функция, которую я использую для печати:

 echo '<pre>'; print_r($tab); echo '</pre>';