问题
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