tags:

views:

1285

answers:

5

I want a version of strreplace() that only replaces the first match in the target string. Is there an easy solution to this, or do I need a hacky solution?

+7  A: 

Can be done with preg_replace:

<?
$str = 'abcdef abcdef abcdef';
// pattern, replacement, string, limit
echo preg_replace('/abc/', '123', $str, 1); // outputs '123def abcdef abcdef'
?>

The magic is in the optional fourth parameter [Limit]. From the documentation:

[Limit] - The maximum possible replacements for each pattern in each subject string. Defaults to -1 (no limit).

karim79
+1, from all the workarounds I can think of this is obviously the best.
Alix Axel
The downside to this method is the performance penalty of regular expressions.
zombat
Another downside is you have to use preg_quote() on the "needle" and escape meta-characters $ and \ in the replacement.
Josh Davis
A: 

The easiest way would be to use regular expression.

The other way is to find the position of the string with strpos() and then an substr_replace()

But i would really go for the RegExp.

Rufinus
+5  A: 

There's no version of it, but the solution isn't hacky at all.

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

Pretty easy, and saves the performance penalty of regular expressions.

zombat
Can be much faster and will use less memory than regular expressions. No idea why someone would vote that down...
Josh Davis
Yeah, someone came through and voted a bunch of the answers down. Always a classy move.
zombat
I like this approach, but the code has an error, the last parameter of substr_replace call should be strlen($needle) instead of strlen($replace).. please beware about that!!
Nelson
A: 

Unfortunately I don't know of any PHP funciton which can do this. You can roll your own fairly easily like this:

function replace_first($find, $replace, $subject) {
    // stolen from the comments at PHP.net/str_replace
    return implode($replace, explode($find, $subject, 1));
}
too much php
+2  A: 

The answers by 'zombat' and 'too much php' are unfortunately not correct. This is a revision to the answer zombat posted (as I don't have enough reputation to post a comment):

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

Note the strlen($needle), instead of strlen($replace). Zombat's example will only work correctly if needle and replace are the same length.

Here's the same functionality in a function with the same signature as PHP's own str_replace:

function str_replace_first($search, $replace, $subject) {
    $pos = strpos($subject, $search);
    if ($pos !== false) {
        $subject = substr_replace($subject, $replace, $pos, strlen($search));
    }
    return $subject;
}

This is the revised answer of 'too much php':

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

Note the 2 at the end instead of 1. Or in function format:

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

I timed the two functions and the first one is twice as fast when no match is found. They are the same speed when a match is found.

Bas