我一直在尽力避免来这里问这个问题,并坚持认为我可以自己解决这个问题。我已经做到了,但我认为无论如何我都会来这里1)分享我的解决方案或2)获得更好的解决方案。
我知道已经有大量的stackoverflow问题,大多数人说使用PEAR库,没有一个是关于我的具体问题。
基本上我希望能够解析bbcode引用标记,但是这个引用可以有可变数量的属性或根本没有属性,所以简单的preg_replace不能像下划线一样工作标签
一个字符串中也可以有多个引用标记,这是我如何解决它的一个例子。任何人都可以建议一个更好的方法来避免多个正则表达式和foreach循环吗?
(应该注意我正在解析示例中的强标记,但是我在我的代码中的其他地方执行此操作,它是我特别挣扎并在此处询问的引号)
$string = "[quote name='Rob' user_id='1' id='1' timestamp='1294120376']
My text here
[/quote]
[quote name='Rob' user_id='1' id='2' timestamp='1302442553']
Lorem ipsum dolor sit amet
[/quote]
Test Comment";
preg_match_all('/\[quote(.*?)](.*?)\[\/quote\]/msi', $string, $matches);
$quotes = array();
foreach($matches[1] as $id => $match)
{
preg_match_all('/(\w*?)=\'(.*?)\'/msi', $match, $attr_matches);
array_push($quotes, array(
'text' => trim($matches[2][$id]),
'attributes' => array_combine($attr_matches[1], $attr_matches[2])
));
}
echo '<pre>'.print_r($quotes,1).'</pre>';
这将输出以下内容:
Array
(
[0] => Array
(
[text] => My text here
[attributes] => Array
(
[name] => Rob
[user_id] => 1
[id] => 1
[timestamp] => 1294120376
)
)
[1] => Array
(
[text] => Lorem ipsum dolor sit amet
[attributes] => Array
(
[name] => Rob
[user_id] => 1
[id] => 2
[timestamp] => 1302442553
)
)
)
然后我只是构建HTML
$bbcode = '';
foreach($quotes as $quote)
{
$attributes = array();
foreach($quote['attributes'] as $key => $value)
{
switch($key)
{
case 'id':
$attributes[] = '<a href="'.site_url('forums/findpost/'.$value).'">Permalink</a>';
break;
case 'name':
if(isset($quote['attributes']['user_id']))
{
$attributes[] = 'By <a href="'.site_url('user/profile/'.$quote['attributes']['user_id'].'/'.$value).'">'.$value.'</a>';
}
else
{
$attributes[] = 'By '.$value;
}
break;
case 'timestamp':
$attributes[] = 'On '.date('d F Y - H:i A', $value);
break;
}
}
if(!empty($attributes))
{
$bbcode .= '<p class="citation">'.implode(' | ', $attributes).'</p>';
}
$bbcode .= '<blockquote>
'.$quote['text'].'
</blockquote>';
}
echo $bbcode;
将输出以下内容:
<p class="citation">By <a href="http://domain.com/user/profile/1/Rob.html">Rob</a> | <a href="http://domain.com/forums/findpost/1.html">Permalink</a> | On 04 January 2011 - 05:52 AM</p>
<blockquote>
My text here
</blockquote>
<p class="citation">By <a href="http://domain.com/user/profile/1/Rob.html">Rob</a> | <a href="http://domain.com/forums/findpost/2.html">Permalink</a> | On 10 April 2011 - 14:35 PM</p>
<blockquote>
Lorem ipsum dolor sit amet
</blockquote>
所以这似乎是一个非常漫长的方式,但我无法理解另一种方法。任何人都...?
答案 0 :(得分:2)
我已经设法提出了我自己更优雅的解决方案,这个解决方案代码更少,并且可以使用嵌套引号。
这只会解析引号,引号内和周围的内容仍然需要从bbcode转换,但是有足够的资源可供使用。
function parse_quote($matches) {
$bbcode = '';
preg_match_all('/(\w*?)=\'(.*?)\'/msi', $matches[1], $attr_matches);
$attributes = array_combine($attr_matches[1], $attr_matches[2]);
if(!empty($attributes))
{
$attribute_strings = array();
foreach($attributes as $key => $value)
{
switch($key)
{
case 'id':
$attribute_strings[] = '<a href="http://domain.com/forums/findpost/'.$value.'">Permalink</a>';
break;
case 'name':
if(isset($quote['attributes']['user_id']))
{
$attribute_strings[] = 'By <a href="http://domain.com/user/profile/'.$attributes['user_id'].'/'.$value.'">'.$value.'</a>';
}
else
{
$attribute_strings[] = 'By '.$value;
}
break;
case 'timestamp':
$attribute_strings[] = 'On '.date('d F Y - H:i A', $value);
break;
}
}
{
$citation = '<p class="citation">'.implode(' | ', $attribute_strings).'</p>'."\n";
}
}
else
{
$citation = '';
}
return $citation.'<blockquote>';
}
$string = "[quote name='Rob' user_id='1' id='1' timestamp='1294120376']
[quote name='Rob' user_id='1' id='2' timestamp='1302442553']
[quote name='Rob' user_id='1' id='3' timestamp='1302442553']
Test at a comment of a third depth
[/quote]
Lorem ipsum dolor sit amet
[/quote]
This is my comment
[/quote]
[b]Test Comment[/b]";
$new_string = str_replace('[/quote]', '</blockquote>', $string);
echo preg_replace_callback('/\[quote(.*?)\]/msi','parse_quote', $new_string);
这应该返回以下
<p class="citation">By Rob | <a href="http://domain.comforums/findpost/1">Permalink</a> | On 04 January 2011 - 05:52 AM</p>
<blockquote>
<p class="citation">By Rob | <a href="http://domain.comforums/findpost/2">Permalink</a> | On 10 April 2011 - 14:35 PM</p>
<blockquote>
<p class="citation">By Rob | <a href="http://domain.comforums/findpost/3">Permalink</a> | On 10 April 2011 - 14:35 PM</p>
<blockquote>
Test at a comment of a third depth
</blockquote>
Lorem ipsum dolor sit amet
</blockquote>
This is my comment
</blockquote>
Test Comment
答案 1 :(得分:0)
所以这似乎是一个非常漫长的方式,但我无法理解另一种方法。
使用正则表达式与BBCode一起使用时,它实际上非常合理......尽管你似乎最后放弃了[b]Test Comment[/b]
。
正如评论中所提到的,此方法将打破您的标记变为可嵌套的瞬间。 I've previously written about that problem,而且几乎唯一合理的解决方案是构建一个“真正的”解析器来处理那种疯狂。我还没有遇到一个正确执行此操作的现有第三方BBCode解析器。
但是,由于您不认为嵌套是个问题,因此此代码应该可以正常工作。不要忘记过滤标签中的属性以获取不友好的字符。如果site_url
没有这样做,那么您已经创建了一个XSS漏洞。