0
function parse($string){
    $counter = 0;
    
    $string = preg_replace("_\[b\](.*?)\[/b\]_si", '<span class="b">'. $counter .'. $1</span>', $string, -1, $counter);
    
    return $string;
}

I'm trying to make a ubb parser, that parses tags and put the counting in front of it:

[b]Hey[/b]
[b]Hello[/b]

Should return this:

<span class="b">1. Hey</span>
<span class="b">2. Hello</span>

But is returning this:

<span class="b">1. Hey</span>
<span class="b">1. Hello</span>

So beside the function above, I've tried this:

function parse($string){
    
    $counter = 0;
    
    $string = preg_replace_callback(("_\[b\](.*?)\[/b\]_si", function(){
        '<span class="b">'. $counter++ .'. $1</span>',
    }, $string);
}

but that, and the function at the top, didn't work. What am I doing wrong and/or could I try?

0

3 Answers 3

3

I would solve it with a small class with the counter as property and the callback is a method of the class.

class Increaser {
    private $counter;

    public function replace($string) {
        $this->counter = 0;

        return preg_replace_callback("_\[b\](.*?)\[/b\]_si", array($this, 'createReplacement'), $string);
    }

    private function createReplacement($matches) {
        ++$this->counter;

        return '<span class="b">'. $this->counter .'. ' . $matches[1] . '</span>';
    }
}
Sign up to request clarification or add additional context in comments.

6 Comments

What is the advantage of having a class?
Your counter will count. Don't know if it's the best solution but only one I can mention.
Your*. ;) Using global variables, counting has worked with preg_replace_callback, but it would display $1 instead of the actual value.
Oops ;-) I'm not native speaker so I mess this things up sometimes in speedy typing. Corrected it. The function to do the replacement gets an arg. Look at edited code in my answer.
Got one more ( than you need after callback :)
|
0

Eventually solved it with the help of TiMESPLiNTER (give him the credit!), didn't know $1 didn't get brought along and that you have to call a variable $matches in the callback function and get $matches[1] instead of $1.

$counter = 1;

function parse(){
    function cb($matches){
        global $counter;

        return '<span class="b">'. $this->counter .'. ' . $matches[1] . '</span>';
    }

    $string = preg_replace_callback("_\[b\](.*?)\[/b\]_si", 'cb', $string);
}

3 Comments

Don't know it this is a good solution and will work if register_globals is set to off. (Just guessing)
Then it's time to start ;-).
Undefined variable $string. I don't believe $this->counter is right either. And parse() doesn't print or return anything.
0

You don't need to declare a global "counter" variable or design a class-based workaround. You can simply use a static variable declaration inside of preg_replace_callback()'s custom function.

Code: (Demo) -- this is the way I would code my own project

$ubbText = <<<TEXT
[b]Hey[/b]
[b]Hello[/b]
TEXT;

echo preg_replace_callback(
         "~\[b](.*?)\[/b]~si",
         function ($m) {
             static $counter = 0;
             return '<span class="b">' . (++$counter) . '. ' . $m[1] . '</span>';
         },
         $ubbText
     );

Alternatively, you could avoid the use of a static declaration and use preg_replace() because your code logic will not possibly replace replacements (an infinite loop is not possible). To be honest, I don't prefer this technique because it involves iterated preg_ function calls which make one replacement per iteration and the regex engine will need to restart from the beginning of the input string each time.

Code: (Demo)

$counter = 0;
do {
    $ubbText = preg_replace(
        "~\[b](.*?)\[/b]~si",
        '<span class="b">' . (++$counter) . '. $1</span>',
         $ubbText,
         1,
         $count
     );
} while ($count);
echo $ubbText;

Output (from both snippets):

<span class="b">1. Hey</span>
<span class="b">2. Hello</span>

p.s. I suppose I should state for the record that your regex pattern will not favorably handle the possibility of nested tags [b] bold [b]re-bold[/b][/b]. If these types of occurrences are not possible in your application's text, then no worries. There are ways to mitigate this vulnerability, but I will not digress in this post. Search Stack Overflow for this if your application requires it.

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.