因此,例如用户输入一些正则表达式匹配,他希望最后一个匹配将被输入字符串替换。
示例:
$str = "hello, world, hello!";
// For now, regex will be for example just word,
// but it should work with match too
replaceLastMatch($str, "hello", "replacement");
echo $str; // Should output "hello, world, replacement!";
答案 0 :(得分:1)
使用negative lookahead确保您只匹配搜索字符串的最后一次出现:
function replaceLastMatch($str, $search, $replace) {
$pattern = sprintf('~%s(?!.*%1$s)~', $search);
return preg_replace($pattern, $replace, $str, 1);
}
用法:
$str = "hello, world, hello!";
echo replaceLastMatch($str, 'h\w{4}', 'replacement');
echo replaceLastMatch($str, 'hello', 'replacement');
输出:
hello, world, replacement!
答案 1 :(得分:0)
以下是我提出的建议:
简短版:
虽然它很容易受到攻击(例如,如果用户使用群组(abc)
,这将会破坏):
function replaceLastMatch($string, $search, $replacement) {
// Escape all / as it delimits the regex
// Construct the regex pattern to be ungreedy at the right (? behind .*)
$search = '/^(.*)' . str_replace('/', '\\/', $search) . '(.*?)$/s';
return preg_replace($search, '${1}' . $replacement . '${2}', $string);
}
更长版本(个人推荐):
此版本允许用户在不干扰此功能的情况下使用组(例如模式((ab[cC])+(XY)*){1,5}
):
function replaceLastMatch($string, $search, $replacement) {
// Escape all '/' as it delimits the regex
// Construct the regex pattern to be ungreedy at the right (? behind .*)
$search = '/^.*(' . str_replace('/', '\\/', $search) . ').*?$/s';
// Match our regex and store matches including offsets
// If regex does not match, return $string as-is
if(1 !== preg_match($search, $string, $matches, PREG_OFFSET_CAPTURE))
return $string;
return substr($string, 0, $matches[1][1]) . $replacement
. substr($string, $matches[1][1] + strlen($matches[1][0]));
}
一个一般的警告:你应该非常小心用户输入,因为它可以做所有令人讨厌的东西。始终为相当“非生产性”的输入做好准备。
<小时/> 说明:
匹配最后功能的核心是?
(贪婪反转)运算符(请参阅Repetition - 中间某处)。
虽然默认情况下重复模式(例如.*
) greedy ,但消耗的尽可能多地匹配,制作模式 ungreedy < / em>(例如.*?
)会尽可能少地匹配 (但仍然匹配)。
因此,在我们的例子中,模式的贪婪前部总是优先于非贪婪的后部,我们的自定义中间部分将匹配最后一个实例。