所以,例如用户输入一些正则表达式匹配,他希望最后一个匹配将被input-string替换。
的例子:
$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!";
使用反向查找以确保只匹配最后出现的搜索字符串:
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!
我是这么想的:
短版:
它是脆弱的(例如,如果用户使用组(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]));
}
一个一般的警告:你应该非常小心用户输入,因为它可以做所有讨厌的事情。要时刻准备好接受那些相当"非生产性"的投入。解释:match last功能的核心是
?
(贪婪反转)运算符(参见Repetition -在中间的某个地方)。虽然重复模式(例如.*
)默认是贪婪的,消耗尽可能多地匹配,使模式不贪婪(例如.*?
)将使其匹配尽可能少(同时仍然匹配)。
因此,在我们的例子中,模式的前贪婪部分将始终优先于后非贪婪部分,而我们自定义的中间部分将匹配可能的最后一个实例。