Используя str_replace, чтобы он действовал только в первом матче? - PullRequest
288 голосов
/ 10 августа 2009

Я хочу версию str_replace(), которая заменяет только первое вхождение $search в $subject. Есть ли простое решение для этого, или мне нужно хакерское решение?

Ответы [ 22 ]

2 голосов
/ 23 ноября 2013

Согласно результатам моего теста, я бы хотел проголосовать за обычный_экспресс, предоставленный karim79. (У меня недостаточно репутации, чтобы проголосовать сейчас!)

Решение от zombat использует слишком много вызовов функций, я даже упрощаю коды. Я использую PHP 5.4 для запуска обоих решений 100 000 раз, и вот результат:

$str = 'Hello abc, have a nice day abc! abc!';
$pos = strpos($str, 'abc');
$str = substr_replace($str, '123', $pos, 3);

==> 1,85 с

$str = 'Hello abc, have a nice day abc! abc!';
$str = preg_replace('/abc/', '123', $str, 1);

==> 1,35 с

Как видите. Производительность preg_replace не так плоха, как думают многие. Поэтому я бы предложил классное решение, если ваш регулярный экспресс не сложен.

2 голосов
/ 08 марта 2014

Для строки

$string = 'OOO.OOO.OOO.S';
$search = 'OOO';
$replace = 'B';

//replace ONLY FIRST occurance of "OOO" with "B"
    $string = substr_replace($string,$replace,0,strlen($search));
    //$string => B.OOO.OOO.S

//replace ONLY LAST occurance of "OOOO" with "B"
    $string = substr_replace($string,$replace,strrpos($string,$search),strlen($search)) 
    //$string => OOO.OOO.B.S

    //replace ONLY LAST occurance of "OOOO" with "B"
    $string = strrev(implode(strrev($replace),explode(strrev($search),strrev($string),2)))
    //$string => OOO.OOO.B.S

Для одного символа

$string[strpos($string,$search)] = $replace;


//EXAMPLE

$string = 'O.O.O.O.S';
$search = 'O';
$replace = 'B';

//replace ONLY FIRST occurance of "O" with "B" 
    $string[strpos($string,$search)] = $replace;  
    //$string => B.O.O.O.S

//replace ONLY LAST occurance of "O" with "B" 
    $string[strrpos($string,$search)] = $replace; 
    // $string => B.O.O.B.S
2 голосов
/ 01 июля 2016

В дополнение к тому, что говорили люди, помните, что вся строка является массивом:

$string = "Lorem ipsum lá lá lá";

$string[0] = "B";

echo $string;

"Borem ipsum lá lá lá"

2 голосов
/ 11 января 2016

=> КОД БЫЛ ПЕРЕСМОТРЕН, поэтому посчитайте некоторые комментарии слишком старыми

И спасибо всем за помощь в улучшении этого

Любая ошибка, пожалуйста, сообщите мне; Я исправлю это сразу после

Итак, давайте перейдем к:

Замена первого 'o' на 'ea' , например:

$s='I love you';
echo str_replace_first('o','ea',$s);

//output: I leave you

Функция:

function str_replace_first($a,$b,$s)
         {
         $w=strpos($s,$a);
         if($w===false)return $s;
         return substr($s,0,$w).$b.substr($s,$w+strlen($a));
         }
2 голосов
/ 11 января 2014

Чтобы расширить ответ зомбата (который я считаю лучшим ответом), я создал рекурсивную версию его функции, которая принимает параметр $limit, чтобы указать, сколько вхождений вы хотите заменить.

function str_replace_limit($haystack, $needle, $replace, $limit, $start_pos = 0) {
    if ($limit <= 0) {
        return $haystack;
    } else {
        $pos = strpos($haystack,$needle,$start_pos);
        if ($pos !== false) {
            $newstring = substr_replace($haystack, $replace, $pos, strlen($needle));
            return str_replace_limit($newstring, $needle, $replace, $limit-1, $pos+strlen($replace));
        } else {
            return $haystack;
        }
    }
}
1 голос
/ 11 апреля 2016

Эта функция в значительной степени вдохновлена ​​ответом @renocor. Это делает функцию многобайтовой безопасной.

function str_replace_limit($search, $replace, $string, $limit)
{
    $i = 0;
    $searchLength = mb_strlen($search);

    while(($pos = mb_strpos($string, $search)) !== false && $i < $limit)
    {
        $string = mb_substr_replace($string, $replace, $pos, $searchLength);
        $i += 1;
    }

    return $string;
}

function mb_substr_replace($string, $replacement, $start, $length = null, $encoding = null)
{
    $string = (array)$string;
    $encoding = is_null($encoding) ? mb_internal_encoding() : $encoding;
    $length = is_null($length) ? mb_strlen($string) - $start : $length;

    $string = array_map(function($str) use ($replacement, $start, $length, $encoding){

        $begin = mb_substr($str, 0, $start, $encoding);
        $end = mb_substr($str, ($start + $length), mb_strlen($str), $encoding);

        return $begin . $replacement . $end;

    }, $string);

    return ( count($string) === 1 ) ? $string[0] : $string;
}
0 голосов
/ 30 мая 2018

Если ваша строка не содержит многобайтовых символов и если вы хотите заменить только один символ, вы можете просто использовать strpos

Здесь функция, которая обрабатывает ошибки

/**
 * Replace the first occurence of given string
 *
 * @param  string $search  a char to search in `$subject`
 * @param  string $replace a char to replace in `$subject`
 * @param  string $subject
 * @return string
 *
 * @throws InvalidArgumentException if `$search` or `$replace` are invalid or if `$subject` is a multibytes string
 */
function str_replace_first(string $search , string $replace , string $subject) : string {
    // check params
    if(strlen($replace) != 1 || strlen($search) != 1) {
        throw new InvalidArgumentException('$search & $replace must be char');
    }elseif(mb_strlen($subject) != strlen($subject)){
        throw new InvalidArgumentException('$subject is an multibytes string');
    }
    // search 
    $pos = strpos($subject, $search);
    if($pos === false) {
        // not found
        return $subject;
    }

    // replace
    $subject[$replace] = $subject;

    return $subject;
}
0 голосов
/ 27 ноября 2017
$str = "Hello there folks!"
$str_ex = explode("there, $str, 2);   //explodes $string just twice
                                      //outputs: array ("Hello ", " folks")
$str_final = implode("", $str_ex);    // glues above array together
                                      // outputs: str("Hello  folks")

Есть еще один дополнительный пробел, но это не имело значения, как это было для сценария backgound в моем случае.

0 голосов
/ 25 января 2012

Легко найти решение, которое заменит только первую или первую пару экземпляров (указав значение счетчика). Существует не так много решений для замены последней или последней пары экземпляров.

Может быть, что-то вроде str_replace ($ find, $ replace, $ subject, -3) должно заменить последние три экземпляра.

В любом случае, просто предложение.

0 голосов
/ 07 мая 2014

Вот простой класс, который я создал, чтобы обернуть наши слегка модифицированные функции str_replace () .

Наша функция php :: str_rreplace () также позволяет вам выполнять ограниченную обратную функцию str_replace (), которая может быть очень полезна при попытке заменить только последние X-й экземпляр (-ы) строки.

В обоих примерах используется preg_replace () .

<?php
class php {

    /**
    * str_replace() from the end of a string that can also be limited e.g. replace only the last instance of '</div>' with ''
    *
    * @param string   $find
    * @param string   $replace
    * @param string   $subject
    * @param int      $replacement_limit | -1 to replace all references
    *
    * @return string
    */
    public static function str_replace($find, $replace, $subject, $replacement_limit = -1) {
        $find_pattern = str_replace('/', '\/', $find);
        return preg_replace('/' . $find_pattern . '/', $replace, $subject, $replacement_limit);
    }

    /**
    * str_replace() from the end of a string that can also be limited e.g. replace only the last instance of '</div>' with ''
    *
    * @param string   $find
    * @param string   $replace
    * @param string   $subject
    * @param int      $replacement_limit | -1 to replace all references
    *
    * @return string
    */
    public static function str_rreplace($find, $replace, $subject, $replacement_limit = -1) {
        return strrev( self::str_replace(strrev($find), strrev($replace), strrev($subject), $replacement_limit) );
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...