Skip to content

Instantly share code, notes, and snippets.

@daqing
Created February 24, 2009 15:20
Show Gist options
  • Save daqing/69613 to your computer and use it in GitHub Desktop.
Save daqing/69613 to your computer and use it in GitHub Desktop.
<?php
$bbcode = '[p][url=http://www.gmail.com][u]gmail[/u][/url]';
$bbcode .= '[b][size=3]foo[/size][/b]';
$bbcode .= '[color=red][u][i]bar[/i][/u][/color][/p]';
$root = new BBCodeNode('root');
$root = build_tree($bbcode, $root);
echo 'BBCode: ', $bbcode, "\n\n";
traverse_tree($root, 'printer', 0);
function build_tree($bbcode, $node)
{
if ($bbcode == '') {
return $node;
}
$i = 0;
if ($bbcode{0} != '[') {
// text node
$text = '';
while ($bbcode{$i} != '[') {
$text .= $bbcode{$i};
++$i;
}
$child = new BBCodeNode($text);
$child->type = 'text';
$child->value = $text;
$child->parentNode = $node;
$node->children[$node->childCount] = $child;
++$node->childCount;
$node = build_tree(substr($bbcode, $i), $node);
return $node;
} else {
++$i;
if ($bbcode{$i} != '/') {
// a open tag
$state = 'in_open_tag';
$open_tag = '';
$param = '';
while ($bbcode{$i} != ']') {
if ($bbcode{$i} != '=') {
$open_tag .= $bbcode{$i};
++$i;
} else {
$state = 'in_param';
break;
}
}
if ($state == 'in_param') {
while($bbcode{++$i} != ']') {
$param .= $bbcode{$i};
}
$state = 'in_open_tag';
}
if ($state == 'in_open_tag' && $bbcode{$i} == ']') {
// open_tag finished
$child = new BBCodeNode($open_tag);
if ($param) {
$child->param = $param;
}
$child->parentNode = $node;
$node->children[$node->childCount] = $child;
++$node->childCount;
$node = build_tree(substr($bbcode, ++$i), $child);
return $node;
} else {
throw new Exception('invalid bbcode, index[' . $i . ']');
}
} else {
// a close tag
// skip close tag
while ($bbcode{++$i} != ']') {
;
}
if ($node->parentNode) {
++$i;
$node->parentNode = build_tree(substr($bbcode, $i), $node->parentNode);
return $node->parentNode;
} else {
throw new Exception('bbcode not match, index[' . $i . ']');
}
}
}
}
function traverse_tree($node, $handler, $depth)
{
$handler($node, $depth);
if ($node->childCount) {
foreach ($node->children as $v) {
traverse_tree($v, $handler, $depth + 1);
}
}
}
function printer($node, $depth)
{
for ($i = 0; $i < $depth; $i++) {
echo ' ';
}
echo 'node(', $node->name;
if ($node->param) {
echo '=', $node->param;
}
echo ")\n";
}
class BBCodeNode
{
public $name = null;
public $parentNode = null;
public $children = array();
public $childCount = 0;
public $type = 'node';
public $value = null;
function __construct($name)
{
$this->name = $name;
}
}
?>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment