How to replace text with a regex pattern and integrate a counter in the replacement text?

牧云@^-^@ 提交于 2021-02-05 10:00:18

问题


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?


回答1:


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>';
    }
}



回答2:


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:


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.



来源:https://stackoverflow.com/questions/19861859/how-to-replace-text-with-a-regex-pattern-and-integrate-a-counter-in-the-replacem

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!