【问题标题】:Avoid replace placeholder found in replacement string避免在替换字符串中找到替换占位符
【发布时间】:2019-06-22 08:24:05
【问题描述】:

假设我有这个字符串:

"my string ? other string ?"
  • 我想替换第一个“?”使用"first param ?"(注意文本中的占位符?)
  • 和第二个"second param".

如果我做一个 preg_replace 我得到这个:

my string first param second param other string ?
          ^^^^^^^^^^^^^^^^^^^^^^^^              ^
                WRONG                    NOT REPLACED

基本上,因为第一个替换也有占位符,preg_replace 愚蠢到替换那个占位符,而不是最后的真正的第二个。

使用preg_replace 编码:

$search = ["?", "?"];
$params = ["first param ?", "second param"];
$query ="first text ? other text ?";

//> Marker in the query are ?, so I create the array to preg_replace
$search = array_fill(0,count($params),'/\?/');
$query = preg_replace(
    $search,                // a list of ?
    $params,                // escaped values
    $query,                 // from query
    1                       // replace only 1 time
);
//output: first text first param second param other text ?

关于如何避免在替换中搜索占位符的任何提示?

带有preg_replace的实时代码:http://sandbox.onlinephpfunctions.com/code/e705ba454d030103344bc826e0fe0bf42d5b7b90

不适用于str_replace

$search = ["?", "?"];
$params = ["first param ?", "second param"];
$query ="first text ? other text ?";

$query = str_replace ($search, $params, $query);
echo $query;

// output: first text first param second param other text first param second param

带有 str_replace 的实时代码: http://sandbox.onlinephpfunctions.com/code/dc259325411ee42de759f145eac78b339f329f74

异常输出

给定:

$search = ["?", "?"];
$params = ["first param ?", "second param"];
$query ="first text ? other text ?";

预期的输出是:

first text first param ? other text second param
           ^^^^^^^^^^^^^            ^^^^^^^^^^^^
         first placeholder         second placeholder

带有 3 个参数的异常输出

$search = ["?", "?", "?"];
$params = ["first param", "second param ?", "third param"];
$query ="first text ? other text ? other chunk ?";

预期的输出是:

first text first param other text  second param ? other chunk third param
           ^^^^^^^^^^^^^            ^^^^^^^^^^^^              ^^^^^^^^^
         first placeholder         second placeholder         third placeholder

我的自定义解决方案

我想出了一个使用preg_split 的可能解决方案,但老实说,这太老套了,肯定有更好的解决方案:

 $parts = preg_split('/(\?)/', $query, -1, PREG_SPLIT_DELIM_CAPTURE);

 foreach($parts as $k=>&$v) {
        // if is odd, then it's a placeholder
        if ($k%2 == 1)
            $v = $params[$k/2];  // replace placeholder with a param
 }

 $query = implode('',$parts);

【问题讨论】:

  • 如果取消限制, 1会怎样?
  • 试过了,不起作用,因为它两次替换了两个占位符,我在原始帖子中添加了实时代码测试
  • 你想使用str_replace()吗?见演示3v4l.org/t4QKq
  • 用 str_replace 尝试过,但它不起作用,因为它多次替换同一个占位符:sandbox.onlinephpfunctions.com/code/…
  • @AlwaysSunny:我在帖子末尾添加了预期的输出

标签: php regex preg-replace


【解决方案1】:

任何自定义替换逻辑都应该用preg_replace_callback实现,例如:

$params = ["first param", "second param ?", "third param"];
$query ="first text ? other text ? other chunk ?";

echo preg_replace_callback('/\?/', function($m) use (&$params) {
    return array_shift($params);
}, $query);

直播代码:http://sandbox.onlinephpfunctions.com/code/33f4804b49103e54e8070e8d9959ec9642930857

【讨论】:

  • 很好,让我创建一个实时 sn-p,完成。非常好,尽管它不是“自定义”替换逻辑,它只是一个非常简单的顺序占位符替换:)
  • 我刚刚更新了我的答案。你有我的意思。
【解决方案2】:

这仅适用于 2 个占位符。

$search = [
    "/^([^?]*)\?/",     # matches everything that is not a question mark in group 1, then a question mark
    "/^(.*)\?/"         # matches everything until last question mark in group 1, then a question mark
];
$params = ["$1first param ?", "$1second param"];

$query = "first text ? other text ?";

$query = preg_replace($search, $params, $query);

echo $query;

输出:

first text first param ? other text second param

【讨论】:

  • Toto +1,但是这个东西是动态的,我不知道有多少$search 会到达这个函数。它需要是通用的
  • @giò:您能否给出 3 个或更多占位符的示例和预期结果?与
【解决方案3】:

这可以使用while() 循环并检查strpos() 来完成,但explode() 是解决此问题的另一种方法:

$params = ['first param ?', 'second param'];
$query = 'my string ? other string ?';
$str = '';

foreach(explode('?', $query, count($params) + 1) as $token) {
    $str .= $token . array_shift($params);
}

echo $str;

live demo here

【讨论】:

  • 是+1,爆炸类似于preg_slit,通过观看sn-p,我认为接受的答案是最简单的解决方案
  • 是的,但不同之处在于explode() 中不涉及 PCRE 层,因为它发生在preg_split() 或其他 preg_* 函数中。所以它应该执行得更快。
【解决方案4】:

试试:

$s = "my string ? other string ?";
$s = preg_replace('/\?/', "first ?", $s, 1);
$s = preg_replace('/((?:^.*?\?)?.*?)\?/', "$1second text", $s);
echo $s;

基于How to skip first regex match?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-09-26
    • 2012-05-11
    • 1970-01-01
    • 1970-01-01
    • 2020-06-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多