preg_replace_callback with array pattern and replacement

I have a function which uses preg_replace() where the pattern and replacements are arrays. I need a counter to track the replacements, so I am converting the function to use preg_replace_callback with a closure, but I can't seem to find a way to distinguish which pattern the match being passed to the callback matches. Is there a way to do array => array replacement using preg_replace_callback?

Ideally this is what I'd like to work, but obviously it won't since $pattern and $replace are evaluated going into the call and not inbetween each replacement

function replaceTags($text)
{
    $i = 1;

    $pattern = array(
        '/\[d\](.*?)\[\/d\]/',
        '/\[s\](.*?)\[\/s\]/',
    );

    $replace = array(
        '<div id="'.($i++).'">$1</div>',
        '<span id="'.($i++).'">$1</span>',
    );

    return preg_replace($pattern, $replace, $text);
}

Answers


If I understand it correctly, you just need to maintain state between calls to your callback function. The ideal way to do this is using a member function. The state is stored in the object instance. Each time you call, you can modify the object, changing your state.

I also added an extra capture to your patterns in order to differentiate between the patterns in the callback.

<?php
class TagReplacer {
    private $counter = 0;

    public function replacer($matches) {
        // modify the state
        $this->counter++;

        // return the replacement text using the state
        if ($matches[1] === "d")
            $tag = 'div';
        else
            $tag = 'span';
        return "<{$tag} id=\"{$this->counter}\">{$matches[2]}</{$tag}>";
    }
}

function replaceTags($text) {
    $stateObject = new TagReplacer();
    $patterns = array(
        '/\[(d)\](.*?)\[\/d\]/',
        '/\[(s)\](.*?)\[\/s\]/',
    );

    return preg_replace_callback(
            $patterns,
            array(&$stateObject, "replacer"),
            $text);
}

echo replaceTags("zzz[d]123[/d]zzz[s]456[/s]zzz[d]78[/d]zzz[s]90[/s]zzz");
?>

The output is

zzz<div id="1">123</div>zzz<span id="3">456</span>zzz<div id="2">78</div>zzz<span id="4">90</span>zzz

I was surprised that the ids are not in numerical order. My guess is that preg_replace_callback iterates through the pattern array doing all the replacements at once for each pattern.


Need Your Help

Error when deleting dynamic array c++

c++ arrays dynamic

I am getting a run time error when my program hits this code. I am sure the delete is causing it, I just don't see what is going wrong.

Facultative relation with Doctrine ORM

symfony1 doctrine relation

How should be implemented facultative one-to-one relation in Doctrine ORM and Symfony? Suppose there are some folders represented in database. Each folder can have a default icon or some custom icon