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


当前回答

$string = 'this is my world, not my world';
$find = 'world';
$replace = 'farm';
$result = preg_replace("/$find/",$replace,$string,1);
echo $result;

其他回答

可以用preg_replace完成:

function str_replace_first($search, $replace, $subject)
{
    $search = '/'.preg_quote($search, '/').'/';
    return preg_replace($search, $replace, $subject, 1);
}

echo str_replace_first('abc', '123', 'abcdef abcdef abcdef'); 
// outputs '123def abcdef abcdef'

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

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

不过,请参阅zombat的回答以获得更有效的方法(大约快3-4倍)。

我想知道哪一个是最快的,所以我都测试了。

下面你会发现:

这个页面上的所有功能的综合列表 对每个贡献进行基准测试(平均执行时间超过10,000次运行) 链接到每个答案(完整代码)


所有功能都在相同的设置下进行测试:

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

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

substr_replace($string, $replace, 0, strlen($search)); [CONTRIBUTED BY] => zombat [OOO.OOO.OOO.S] => B.OOO.OOO.S [AVERAGE TIME] => 0.0000062883 [SLOWER BY] => FASTEST replace_first($search, $replace, $string); [CONTRIBUTED BY] => too much php [OOO.OOO.OOO.S] => B.OOO.OOO.S [AVERAGE TIME] => 0.0000073902 [SLOWER BY] => 17.52% preg_replace($search, $replace, $string, 1); [CONTRIBUTED BY] => karim79 [OOO.OOO.OOO.S] => B.OOO.OOO.S [AVERAGE TIME] => 0.0000077519 [SLOWER BY] => 23.27% str_replace_once($search, $replace, $string); [CONTRIBUTED BY] => happyhardik [OOO.OOO.OOO.S] => B.OOO.OOO.S [AVERAGE TIME] => 0.0000082286 [SLOWER BY] => 30.86% str_replace_limit($search, $replace, $string, $count, 1); [CONTRIBUTED BY] => bfrohs - expanded renocor [OOO.OOO.OOO.S] => B.OOO.OOO.S [AVERAGE TIME] => 0.0000083342 [SLOWER BY] => 32.54% str_replace_limit($search, $replace, $string, 1); [CONTRIBUTED BY] => renocor [OOO.OOO.OOO.S] => B.OOO.OOO.S [AVERAGE TIME] => 0.0000093116 [SLOWER BY] => 48.08% str_replace_limit($string, $search, $replace, 1, 0); [CONTRIBUTED BY] => jayoaK [OOO.OOO.OOO.S] => B.OOO.OOO.S [AVERAGE TIME] => 0.0000093862 [SLOWER BY] => 49.26%


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

Substr_replace ($string, $replace, strrpos($string, $search), strlen($search)); [贡献BY] => oLinkSoftware - modified僵尸 [OOO.OOO.OOO。S] => ooo [平均时间]=> 0.0000068083 [慢]=>最快 Strrev (implode(Strrev ($replace), explosion (Strrev ($search), Strrev ($string), 2))); [贡献BY] => oLinkSoftware [OOO.OOO.OOO。S] => ooo [平均时间]=> 0.0000084460 [慢]=> 24.05%

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));
}

这个函数很大程度上受到@ renoor回答的启发。 它使函数多字节安全。

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;
}

如果你的字符串不包含任何多字节字符,如果你只想替换一个字符,你可以简单地使用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;
}