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


当前回答

不幸的是,我不知道任何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));
}

其他回答

我创建了这个小函数,用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;
}

使用示例:

$search  = 'foo';
$replace = 'bar';
$string  = 'foo wizard makes foo brew for evil foo and jack';
$limit   = 2;

$replaced = str_replace_limit($search, $replace, $string, $limit);

echo $replaced;
// bar wizard makes bar brew for evil foo and jack

为了扩展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;
        }
    }
}

编辑:两个答案都已更新,现在是正确的。我将把答案留下,因为函数时间仍然是有用的。

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

$pos = strpos($haystack,$needle);
if ($pos !== false) {
    $newstring = substr_replace($haystack,$replace,$pos,strlen($needle));
}

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

这是修改后的“too much php”的答案:

implode($replace, explode($search, $subject, 2));

注意最后的2而不是1。或函数格式:

function str_replace_first($search, $replace, $subject) {
    return implode($replace, explode($search, $subject, 2));
}

我对这两个函数进行了计时,当没有找到匹配时,第一个函数的速度是原来的两倍。当找到匹配时,它们的速度是一样的。

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

另一种方法是用strpos()找到字符串的位置,然后用substr_replace()

但我真的会选择RegExp。

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

下面你会发现:

这个页面上的所有功能的综合列表 对每个贡献进行基准测试(平均执行时间超过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%