【问题标题】:PHP preg_replace_callback, replace only 1 backreference?PHP preg_replace_callback,只替换1个反向引用?
【发布时间】:2012-08-11 05:36:26
【问题描述】:

使用preg_replace_callback,是否可以只替换一个反向引用?还是我必须全部退回?

我只是想用引号将令牌的默认值括起来。

$str = 'This is a {$token|token was empty}';
$str = preg_replace_callback('~{\$\w+\|(.*)?}~i', function($match) {
    //$match[1] is "token was empty"
    //I want to just replace $match[1], but it needs me to return the whole thing
}, $str);

我是否必须获取更多的反向引用,以便能够构建一个新版本的令牌并返回它,我不能只替换反向引用 1?谢谢。

【问题讨论】:

    标签: php regex string replace


    【解决方案1】:

    我是否必须获取更多的反向引用,以便能够构建一个新版本的令牌并返回它,我不能只替换反向引用 1?

    你有两个选择:

    1. 如您所说,使用额外的反向引用来构造替换字符串,或者
    2. 使用环视来仅匹配您要替换的部分。

    通常我建议使用第一种方法,因为第二种方法效率较低,并且在某些情况下可能导致无效匹配(当前瞻和后向可能重叠时)。这种情况下就没有问题了。

    第二个选项的示例是:

    preg_replace_callback('~{\$\w+\|\K(?:[^{}]+)?(?=})~i', function($match){
        // $match[0] contains what used to be the first capturing group.
        // return the value you want to replace it with
        // (you can still use the capturing group if you want, but it's unnecessary)
    });
    
    • \K 是一种从实际匹配中排除它之前的所有内容的方法(就像我们在那里有一个可变长度的lookbehind)。
    • (?=}) 是一个前瞻,表示以下必须是 },但不包含在它自己的匹配中。

    【讨论】:

    • 我很确定这是不可能的。非常酷,但肯定更神秘一点。
    • @Stephen,您可以使用/x 使其更具可读性,例如:'/{\$\w+\| \K [^{}]* (?= } )/ix'(也删除了无用组)
    【解决方案2】:

    你会想要使用这样的正则表达式,而不是:

    ~\{\$(\w+?)(?:\|(.+?))?\}~i
    

    然后,您可以轻松查看传递给回调的内容:

    $str = 'This is a {$token|token was empty}';
    $str = preg_replace_callback('~\{\$(\w+?)(?:\|(.+?))?\}~i', function($match) {
        var_dump($match);
        exit;
    }, $str);
    

    输出:

    array(3) {
      [0]=>
      string(24) "{$token|token was empty}"
      [1]=>
      string(5) "token"
      [2]=>
      string(15) "token was empty"
    }
    

    从那里,您可以检查是否设置了$match[1],如果设置了,则返回其值,否则返回$match[2]

    $foo = 'foo';
    $str = 'Foo: {$foo|not set}, Bar: {$bar|not set}';
    $str = preg_replace_callback('~\{\$(\w+?)(?:\|(.+?))?\}~i', function($match) {
        if (isset($GLOBALS[$match[1]])) {
            return $GLOBALS[$match[1]];
        } else {
            return $match[2];
        }
    }, $str);
    var_dump($str);
    

    输出:

    string(22) "Foo: foo, Bar: not set"
    

    注意:我在这里使用$GLOBALS 仅用于演示目的。如果可能的话,我建议使用 PHP 5.4 的闭包绑定,因为那时你可以为闭包分配一个特定的对象作为上下文(例如你的模板/视图对象或任何包含你试图替换的变量) .如果您不使用 PHP 5.4,您也可以使用语法 function($match) use ($obj),其中 $obj 是您的上下文,然后在您的闭包中检查 isset($obj->{$match[1]})

    【讨论】:

      【解决方案3】:

      我最近想出了一种更简单的方法来做到这一点。 例如;如果我想匹配 \w+\d+\w+ 并且只更改数字。

      $value = preg_replace_callback('~(\w+)(\d+)(\w+)~', function($match) {
          $match[2] = $match[2] * 2;//Do whatever I want to $match[2]
          return $match[1] . $match[2] . $match[3];
      }, $value);
      

      很干净!

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-08-09
        • 2017-01-30
        • 1970-01-01
        • 1970-01-01
        • 2013-01-17
        • 2017-08-31
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多