How to replace only the last match of a string wit

2020-02-10 08:09发布

问题:

I have to replace the last match of a string (for example the word foo) in HTML document. The problem is that the structure of the HTML document is always random.

I'm trying to accomplish that with preg_replace, but so far I know how to replace only the first match, but not the last one.

Thanks.

回答1:

Use negative look after (?!...)

$str = 'text abcd text text efgh';
echo preg_replace('~text(?!.*text)~', 'bar', $str),"\n";

output:

text abcd text bar efgh


回答2:

A common approach to match all text to the last occurrence of the subsequent pattern(s) is using a greedy dot, .*. So, you may match and capture the text before the last text and replace with a backreference + the new value:

$str = 'text abcd text text efgh';
echo preg_replace('~(.*)text~su', '${1}bar', $str);
// => text abcd text bar efgh

If text is some value inside a variable that must be treated as plain text, use preg_quote to ensure all special chars are escaped correctly:

preg_replace('~(.*)' . preg_quote($text, '~') . '~su', '${1}bar', $str)

See the online PHP demo and a regex demo.

Here, (.*) matches and captures into Group 1 any zero or more chars (note that the s modifier makes the dot match line break chars, too), as many as possible, up to the rightmost (last) occurrence of text. If text is a Unicode substring, the u modifier comes handy in PHP (it enables (*UTF) PCRE verb allowing parsing the incoming string as a sequence of Unicode code points rather than bytes and the (*UCP) verb that makes all shorthand character classes Unicode aware - if any).

The ${1} is a replacement backreference, a placeholder holding the value captured into Group 1 that lets restore that substring inside the resulting string. You can use $1, but a problem might arise if the $text starts with a digit.



回答3:

An example

<?php

$str = 'Some random text';
$str_Pattern = '/[^ ]*$/';

preg_match($str_Pattern, $str, $results);

print $results[0];

?> 


回答4:

Of course the accepted solution given here is correct. Nevertheless you might also want to have a look at this post. I'm using this where no pattern is needed and the string does not contain characters that could not be captured by the functions used (i.e. multibyte ones). I also put an additional parameter for dis/regarding case.

The first line then is:

$pos = $case === true ? strripos($subject, $search) : strrpos($subject, $search);

I have to admit that I did not test the performance. However, I guess that preg_replace() is slower, specially on large strings.