如何使用preg_replace仅替换字符串的最后一个匹配项?

9

我需要替换HTML文档中最后一个匹配的字符串(例如单词foo)。问题是HTML文档的结构总是随机的。

我尝试使用preg_replace来实现这一点,但到目前为止我只知道如何替换第一个匹配,而不是最后一个。

谢谢。


1
请参考解析HTML的最佳方法。以下是一个示例。 - Gordon
1
如果你知道如何替换最后一个匹配项,你可以简单地反转字符串,进行替换,然后再次反转 ;) - Paul Scheltema
4个回答

20

使用负向先行断言 (?!...)

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

输出:

text abcd text bar efgh

1
@AhmetErkanÇELİK:只需在正则表达式开头添加(?s)即可。 - Toto

6

匹配所有文本直到最后一个出现的模式的常见方法是使用贪婪点.*,因此,您可以匹配并捕获最后一个text之前的文本,并使用反向引用+新值进行替换:

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

如果text是一个变量中的某个值,必须被视为纯文本,则使用preg_quote来确保正确转义所有特殊字符:(参考链接)
preg_replace('~(.*)' . preg_quote($text, '~') . '~su', '${1}bar', $str)

请查看在线PHP演示正则表达式演示

这里的(.*)匹配并且捕获到第一组中的任何零个或多个字符(注意,s修饰符让点号也匹配换行符),尽可能多地匹配,直到text的最右(最后)出现位置。如果text是一个Unicode子字符串,那么在PHP中使用u修饰符很方便(它启用了(*UTF) PCRE动词,使得解析传入的字符串作为Unicode代码点序列而不是字节,并且(*UCP)动词可以使所有简写字符类意识到Unicode - 如果有的话)。

${1}是替换反向引用,它是一个占位符,保存了捕获到第一组中的值,可以将该子字符串恢复到结果字符串中。您可以使用$1,但是问题可能出现在$text以数字开头时


1
这个“死帖复活”是必要的,因为之前的回答不够完美、不完整或者不正确。 - mickmackusa

0

一个例子

<?php

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

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

print $results[0];

?> 

0

当然,这里给出的被接受的解决方案是正确的。不过你也可以看看this帖子。我在没有需要模式的情况下使用它,并且字符串不包含无法被函数捕获的字符(即多字节字符)。我还添加了一个附加参数来忽略/区分大小写。

第一行代码如下:

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

我必须承认我没有测试过性能。不过,我猜测 preg_replace() 在处理大字符串时会比较慢。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接