12

I have this code :

$count = 0;    
preg_replace('/test/', 'test'. $count, $content,-1,$count);

For every replace, I obtain test0.

I would like to get test0, test1, test2 etc..

1

6 Answers 6

18

Use preg_replace_callback():

$count = 0;
preg_replace_callback('/test/', 'rep_count', $content);

function rep_count($matches) {
  global $count;
  return 'test' . $count++;
}
Sign up to request clarification or add additional context in comments.

Comments

6

Use preg_replace_callback():

class TestReplace {
    protected $_count = 0;

    public function replace($pattern, $text) {
        $this->_count = 0;
        return preg_replace_callback($pattern, array($this, '_callback'), $text);
    }

    public function _callback($matches) {
        return 'test' . $this->_count++;
    }
}

$replacer = new TestReplace();
$replacer->replace('/test/', 'test test test'); // 'test0 test1 test2'

Note: Using global is the hard-and-fast solution but it introduces some problems, so I don't recommend it.

2 Comments

Global has no more problems than the overcomplicated object solution. People get stuck on globals in PHP because of the C/C++/etc stigmatism, which is misplaced. Globals in PHP are simply request-scoped variables. Less hand-wringing, more pragmatism.
A CLASS here is not needed and may confuse the answer for this question. You just may give a clean example of using "preg_replace_callback"
4

Following the release of PHP5.3 we can now use a closure and the use keyword to get around the global issue raised by Emil above:

    $text = "item1,\nitem2,\nFINDME:23623,\nfoo1,\nfoo2,\nfoo3,\nFINDME:923653245,\nbar1,\nbar2,\nFINDME:43572342,\nbar3,\nbar4";
$pattern = '/FINDME:(\d+)/';
$count = 1;
$text = preg_replace_callback(  $pattern
                            ,   function($match) use (&$count) {
                                    $str = "Found match $count: {$match[1]}!";
                                    $count++;
                                    return $str;
                                }
                            ,   $text
                            );
echo "<pre>$text</pre>";

Which returns:

item1,
item2,
Found match 1: 23623!,
foo1,
foo2,
foo3,
Found match 2: 923653245!,
bar1,
bar2,
Found match 3: 43572342!,
bar3,
bar4

Note the use (&$count) following the function name - this allows us to read $count in the scope of the function (the & making it passed by reference and therefore writeable from the scope of the function).

Comments

3

Also, if you want to avoid using global:

$count = 0; preg_replace_callback('/test/', function rep_count($matches) use (&$count) { return 'test' . $count++; }, $content);

Comments

3

You only have to define a static variable in the callback function:

$result = preg_replace_callback('/test/', function ($m) {
    static $count = 0;
    return 'test' . $count++;
}, $content);

This way you don't pollute the global namespace.


For this specific case you can also use simple functions:

$parts = explode('test', $content);
$end = array_pop($parts);
$result = '';

foreach($parts as $k=>$v) {
    $result .= 'test' . $k;
}

$result .= $end;

Comments

2

preg_replace_callback() will allow you to operate upon the match before returning it for subsequent replacement.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.