Isolate that latest occurring sequence of letters (this is a primitive definition of a "word"), then call strrev()
on it.
To allow for potential non-letter characters between the last "word" and the end of the string, look (without extending the matched string) for zero or more non-letters immediately before the end of the string.
Code: (Demo)
echo preg_replace_callback(
'~[a-z]+(?=[^a-z]*$)~i',
fn($m) => strrev($m[0]),
$string
);
Breakdown:
~ #starting pattern delimiter
[a-z]+ #one or more letters
(?= #start lookahead
[^a-z]* #zero or more non-letters
$ #require the end of the input string
) #end of lookahead
~ #ending pattern delimiter
i #case-insensitive pattern flag
Mutations:
i like to eat apple
becomes i like to eat elppa
orange
becomes egnaro
Surprise!
becomes esirpruS!
An alternative pattern is:
~.*\K\b[a-z]+~i
This greedily matches any character until reaching a word boundary then matching the latest occurring sequence of letters. \K
means "Keep all matched characters ftom this point onward". The greedy zero-or-more quantifier (*
) ensures that only the last "word" is matched.