Here is a tight little regex with \K
that allows you to replace the nth occurrence of a string without repeating the needle in the pattern. If your search string is dynamic and might contain characters with special meaning, then preg_quote()
is essential to the integrity of the pattern.
If you wanted to statically write the search string and nth occurrence into your pattern, it could be:
(?:.*?\K ){8}
- or more efficiently for this particular case:
(?:[^ ]*\K ){8}
\K
tells the regex pattern to "forget" any previously matched characters in the fullstring match. In other words, "restart the fullstring match" or "Keep from here". In this case, the pattern only keeps the 8th space character.
Code: (Demo)
function replaceNth(string $input, string $find, string $replacement, int $nth = 1): string {
$pattern = '/(?:.*?\K' . preg_quote($find, '/') . '){' . $nth . '}/';
return preg_replace($pattern, $replacement, $input, 1);
}
echo replaceNth($originalString, $findString, $newWord, $nthOccurrence);
// Hello world, what do you think of today's beautiful weather
Another perspective on how to grapple the asked question is: "How to insert a new string after the nth instance of a search string?" Here is a non-regex approach that limits the explosions, prepends the new string to the last element then re-joins the elements. (Demo)
$originalString = "Hello world, what do you think of today's weather";
$findString = ' ';
$nthOccurrence = 8;
$newWord = 'beautiful '; // notice that leading space was removed
function insertAfterNth($input, $find, $newString, $nth = 1) {
$parts = explode($find, $input, $nth + 1);
$parts[$nth] = $newString . $parts[$nth];
return implode($find, $parts);
}
echo insertAfterNth($originalString, $findString, $newWord, $nthOccurrence);
// Hello world, what do you think of today's beautiful weather