Php 使用str_replace使其仅在第一次匹配时起作用?

Php 使用str_replace使其仅在第一次匹配时起作用?,php,string,Php,String,我想要一个版本的str_replace(),它只替换$subject中第一次出现的$search。是否有一个简单的解决方案,或者我需要一个黑客解决方案?可以通过以下方式完成: 神奇之处在于可选的第四个参数[Limit]。从文件中: [限制]-可能的最大值 每种模式中每种模式的替换 主题字符串。默认值为-1(否) 限制) 但是,请参阅以获得更有效的方法(大约快3-4倍)。最简单的方法是使用正则表达式 另一种方法是使用strpos()和substr_replace()查找字符串的位置 但是我真的会选

我想要一个版本的
str_replace()
,它只替换
$subject
中第一次出现的
$search
。是否有一个简单的解决方案,或者我需要一个黑客解决方案?

可以通过以下方式完成:

神奇之处在于可选的第四个参数[Limit]。从文件中:

[限制]-可能的最大值 每种模式中每种模式的替换 主题字符串。默认值为-1(否) 限制)



但是,请参阅以获得更有效的方法(大约快3-4倍)。

最简单的方法是使用正则表达式

另一种方法是使用strpos()和substr_replace()查找字符串的位置


但是我真的会选择RegExp。

没有它的版本,但是解决方案一点也不粗糙

$pos = strpos($haystack, $needle);
if ($pos !== false) {
    $newstring = substr_replace($haystack, $replace, $pos, strlen($needle));
}
非常简单,并且节省了正则表达式的性能损失



好处:如果您想替换最后一次出现的内容,只需使用
strrpos
代替
strpos

不幸的是,我不知道有任何PHP函数可以做到这一点。
您可以像这样轻松地滚动自己的屏幕:

function replace_first($find, $replace, $subject) {
    // stolen from the comments at PHP.net/str_replace
    // Splits $subject into an array of 2 items by $find,
    // and then joins the array with $replace
    return implode($replace, explode($find, $subject, 2));
}
编辑:两个答案都已更新,现在都是正确的。我将留下答案,因为函数计时仍然有用

不幸的是,“僵尸”和“太多php”的答案并不正确。这是对zombat发布的答案的修订(因为我没有足够的声誉发表评论):

注意strlen($needle),而不是strlen($replace)。Zombat的示例只有在“针”和“替换”长度相同时才能正常工作

以下是与PHP自己的str_replace具有相同签名的函数中的相同功能:

function str_replace_first($search, $replace, $subject) {
    $pos = strpos($subject, $search);
    if ($pos !== false) {
        return substr_replace($subject, $replace, $pos, strlen($search));
    }
    return $subject;
}
这是“太多php”的修订答案:

implode($replace, explode($search, $subject, 2));
注意末尾的2而不是1。或以函数格式:

function str_replace_first($search, $replace, $subject) {
    return implode($replace, explode($search, $subject, 2));
}
我对这两个函数进行了计时,当没有找到匹配项时,第一个函数的速度是原来的两倍。当找到匹配项时,它们的速度相同。

我创建了这个小函数,它用limit替换字符串对字符串(区分大小写),而不需要Regexp。它很好用

function str_replace_limit($search, $replace, $string, $limit = 1) {
    $pos = strpos($string, $search);

    if ($pos === false) {
        return $string;
    }

    $searchLen = strlen($search);

    for ($i = 0; $i < $limit; $i++) {
        $string = substr_replace($string, $replace, $pos, $searchLen);

        $pos = strpos($string, $search);

        if ($pos === false) {
            break;
        }
    }

    return $string;
}
为了进一步扩展,我编写了一个与
str\u replace()
完全向后兼容的函数。也就是说,您可以用
str_replace_limit()
替换
str_replace()
所有出现的
str_replace()
,而不会弄乱任何东西,即使是那些使用数组进行
$search
$replace
和/或
$subject
的人

如果您想用
($string===strval(intval(strval($string)))
替换函数调用,那么该函数可以是完全自包含的,但我建议您不要这样做,因为
valid\u integer()
在处理作为字符串提供的整数时是非常有用的函数

注意:只要可能,
str\u replace\u limit()
将使用
str\u replace()
代替,因此对
str\u replace()
的所有调用都可以替换为
str\u replace\u limit()

用法 2个替代品——bbcbbc

1件替换件——bbcabc

2个替代品——bbcbbc

作用
您可以使用:

function str_replace_once($str_pattern, $str_replacement, $string){ 

        if (strpos($string, $str_pattern) !== false){ 
            $occurrence = strpos($string, $str_pattern); 
            return substr_replace($string, $str_replacement, strpos($string, $str_pattern), strlen($str_pattern)); 
        } 

        return $string; 
    } 
从php.net中找到此示例

用法:

$string = "Thiz iz an examplz";
var_dump(str_replace_once('z','Z', $string)); 
输出:

ThiZ iz an examplz

这可能会稍微降低性能,但这是最简单的解决方案。

根据我的测试结果,我想投票选择karim79提供的常规\u express。(我现在没有足够的声誉去投票!)

来自zombat的解决方案使用了太多的函数调用,我甚至简化了代码。我使用PHP5.4运行这两个解决方案100000次,结果如下:

$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的性能并不像许多人想象的那么差。因此,如果您的正则表达式不复杂,我建议使用经典的解决方案。

为了扩展zombat的答案(我认为这是最好的答案),我创建了他的函数的递归版本,该函数采用了一个
$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;
        }
    }
}
函数str\u replace\u limit($haystack,$needle,$replace,$limit,$start\u pos=0){
如果字符串的($limit)

$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

我想知道哪一个跑得最快,所以我测试了它们

您将在下面找到:

  • 此页面上提供的所有功能的综合列表
  • 每个施工的基准测试(平均执行时间超过10000次)
  • 每个答案的链接(完整代码)

使用相同的设置测试所有功能:

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

仅替换字符串中第一个出现的字符串的函数:


仅替换字符串中最后出现的字符串的函数:


我创建了一个简单的类来包装我们稍加修改的函数

我们的php::str_rreplace()函数还允许您执行一个反向的、有限的str_replace(),这在尝试仅替换字符串的最后一个X实例时非常方便

这两个例子都使用


代码修改了,所以请考虑一些旧的

的注释。 感谢大家帮助我改进这一点

如果有任何问题,请与我联系,我会马上解决

因此,让我们开始:

将第一个'o'替换为'ea',例如:

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

//output: I leave you
职能:

function str_replace_first($this,$that,$s)
         {
         $w=strpos($s,$this);
         if($w===false)return $s;
         return substr($s,0,$w).$that.substr($s,$w+strlen($this));
         }

此函数深受@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;
}
函数str\u replace\u limit($search,$replace,$string,$limit)
{
$i=0;
$searchLength=mb_strlen($search);
而($pos=mb_strpos($string$
$str = 'Hello abc, have a nice day abc! abc!';
$pos = strpos($str, 'abc');
$str = substr_replace($str, '123', $pos, 3);
$str = 'Hello abc, have a nice day abc! abc!';
$str = preg_replace('/abc/', '123', $str, 1);
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;
        }
    }
}
$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
$string = 'OOO.OOO.OOO.S';
$search = 'OOO'; 
$replace = 'B';
[CONTRIBUTED BY] => zombat
[OOO.OOO.OOO.S] => B.OOO.OOO.S
[AVERAGE TIME] => 0.0000062883
[SLOWER BY] => FASTEST
[CONTRIBUTED BY] => too much php
[OOO.OOO.OOO.S] => B.OOO.OOO.S
[AVERAGE TIME] => 0.0000073902
[SLOWER BY] => 17.52%
[CONTRIBUTED BY] => karim79
[OOO.OOO.OOO.S] => B.OOO.OOO.S
[AVERAGE TIME] => 0.0000077519
[SLOWER BY] => 23.27%
[CONTRIBUTED BY] => happyhardik
[OOO.OOO.OOO.S] => B.OOO.OOO.S
[AVERAGE TIME] => 0.0000082286
[SLOWER BY] => 30.86%
[CONTRIBUTED BY] => bfrohs - expanded renocor
[OOO.OOO.OOO.S] => B.OOO.OOO.S
[AVERAGE TIME] => 0.0000083342
[SLOWER BY] => 32.54%
[CONTRIBUTED BY] => renocor
[OOO.OOO.OOO.S] => B.OOO.OOO.S
[AVERAGE TIME] => 0.0000093116
[SLOWER BY] => 48.08%
[CONTRIBUTED BY] => jayoaK
[OOO.OOO.OOO.S] => B.OOO.OOO.S
[AVERAGE TIME] => 0.0000093862
[SLOWER BY] => 49.26%
[CONTRIBUTED BY] => oLinkSoftware - modified zombat
[OOO.OOO.OOO.S] => OOO.OOO.B.S
[AVERAGE TIME] => 0.0000068083
[SLOWER BY] => FASTEST
[CONTRIBUTED BY] => oLinkSoftware
[OOO.OOO.OOO.S] => OOO.OOO.B.S
[AVERAGE TIME] => 0.0000084460
[SLOWER BY] => 24.05%
<?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) );
    }
}
function str_replace_once($search, $replace, $subject) {
    $pos = strpos($subject, $search);
    if ($pos === false) {
        return $subject;
    }

    return substr($subject, 0, $pos) . $replace . substr($subject, $pos + strlen($search));
}
$s='I love you';
$s=str_replace_first('o','ea',$s);
echo $s;

//output: I leave you
function str_replace_first($this,$that,$s)
         {
         $w=strpos($s,$this);
         if($w===false)return $s;
         return substr($s,0,$w).$that.substr($s,$w+strlen($this));
         }
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;
}
$string = "Lorem ipsum lá lá lá";

$string[0] = "B";

echo $string;
$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")
/**
 * 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;
}
<?php
echo replaceFirstMatchedChar("&", "?", "/property/details&id=202&test=123#tab-6");

function replaceFirstMatchedChar($searchChar, $replaceChar, $str)
{
    for ($i = 0; $i < strlen($str); $i++) {

        if ($str[$i] == $searchChar) {
            $str[$i] = $replaceChar;
            break;
        }
    }
    return $str;
}
$str = "/property/details&id=202&test=123#tab-6p";
$position = strpos($str,"&");
echo substr_replace($str,"?",$position,1);