PHP preg_replace_callback,如何仅替换一个反向引用?

3
使用 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?谢谢。

3个回答

4
我需要抓取更多的反向引用来构建新版本的标记,才能返回它,我不能只替换反向引用1吗?
你有两个选择:
1.使用额外的反向引用来构建替换字符串,就像你说的那样,或者
2.使用lookaround仅匹配您想要替换的部分。
通常我建议使用第一种方法,因为第二种方法效率稍低,并且在某些情况下可能会导致无效匹配(当前后查找重叠时)。在这种情况下不会有问题。
第二个选项的示例:
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 是一种排除实际匹配之前的所有内容的方法(就像我们在变量长度的后顾条件中一样)。
  • (?=}) 是一个向前查看,表示接下来必须是 } ,但不包括它在匹配结果中。

我相当确定这是不可能的。非常酷,但肯定有点更加神秘。 - Farzher
@Stephen,您可以使用 /x 使其更易读,例如:'/{\$\w+\| \K [^{}]* (?= } )/ix'(也删除了无用的组)。 - Qtax

3
您需要使用这样的正则表达式: ```

您需要使用这样的正则表达式:

```
~\{\$(\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]})


1

我最近想到了一种更简单的方法来做这件事。 例如:如果我想匹配\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);

非常干净!


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