PHP preg_replace_callback, replace only 1 backreference?

后端 未结 3 2026
一个人的身影
一个人的身影 2021-01-20 05:12

Using preg_replace_callback, is it possible to replace only one backreference? Or do I have to return the entire thing?

I\'m just trying to wrap the tok

相关标签:
3条回答
  • 2021-01-20 05:50

    You'll want to use a regex like this, instead:

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

    Then, you can easily see what's being passed to your callback:

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

    Output:

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

    And from there, you can check if $match[1] is set, and if so, return its value, otherwise, return $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);
    

    Output:

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

    Note: I'm making use of $GLOBALS here for demonstration purposes only. I'd suggest making use of PHP 5.4's closure binding, if at all possible, since then you can assign the closure a specific object as context (e.g. your template/view object or whatever contains the variables you're trying to substitute). If you aren't using PHP 5.4, you can also use the syntax function($match) use ($obj), where $obj is your context, and then check isset($obj->{$match[1]}) inside your closure instead.

    0 讨论(0)
  • 2021-01-20 06:09

    I recently came up with a way more simple way of doing this. For example; if I want to match \w+\d+\w+ and only change the digits.

    $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);
    

    Very clean!

    0 讨论(0)
  • 2021-01-20 06:10

    Do I have to grab more backreferences so I'm able to build out a new version of the token and return that, I can't just replace backreference 1?

    You have two options:

    1. Use extra backreferences to construct the replacement string, as you said, or
    2. use lookarounds to only match the part you want to replace.

    Usually I recommend using the first approach as the second is a bit less efficient and can lead to invalid matches in some cases (when the lookahead and behind can overlap). In this case there would be no problem tho.

    Example of the second option would be:

    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 is a way to exclude everything before it from the actual match (like if we had a variable length lookbehind there).
    • (?=}) is a lookahead, saying that the following has to be a } but does not include it in the match it self.
    0 讨论(0)
提交回复
热议问题