Let's say we have a tag called test, i.e. [code]
.
What I'd like to do, is I'd like to only allow up to X other [code]
tags inside of every main [code]
tag in a string, which means the most inner ones would get removed.
So, for example, if X = 4, the following string:
[code]a[code]b[code]c[code]d[code]e[code]f[code]g[/code][/code][/code][/code][/code][/code][/code]
Would become:
[code]a[code]b[code]c[code]d[code]e[/code][/code][/code][/code][/code]
And the following string:
[code]a[code]b[code]c[code]d[code]TEST[/code][code]e[code]f[code]g[/code][/code][/code][/code][/code][/code][/code]
Would become:
[code]a[code]b[code]c[code]d[code]TEST[/code][code]e[/code][/code][/code][/code][/code]
The goal here is to not have more than a few nested [code] elements inside of a code element, so it doesn't get too messy.
I'm wondering how to implement this, just trying to think of an algorithm and would appreciate any suggestions.
This is gonna be quite a waste since it would be so easy to add multiple tag support and so on here. You pretty much have to do fully blown out tree parsing either way.
Note that invalid input is not handled in any way, tags must be properly balanced
function get_node_contents( $node ) {
$orig = $node;
$ret = "[code]" . $node->content;
if( @$node->children ) {
foreach( $node->children as $node ) {
$ret .= get_node_contents( $node );
}
}
if( @$orig->endContent ) {
$ret .= $orig->endContent;
}
return $ret."[/code]";
}
function reduce_depth( $str, $maxDepth = 4 ) {
$index = 0;
$len = strlen( $str );
$reg = '/(\[code\]|\[\/code\])/';
$root = new stdClass;
$root->children = array();
$depth = 0;
$ret = "";
$pos = strpos( $str, "[code]" );
if( $pos ) {
$ret .= substr( $str, 0, $pos - 0);
}
while( $index < $len ) {
if( !preg_match( $reg, $str, $matches, PREG_OFFSET_CAPTURE, $index )) {
break;
}
$index = ( $matches[1][1] + strlen( $matches[1][0] ) );
$tag = $matches[1][0];
$next = preg_match( $reg, $str, $matches, PREG_OFFSET_CAPTURE, $index );
$content = "";
if( $next ) {
$content = substr( $str, $index, $matches[1][1] - $index );
}
if( $tag === "[code]" ) {
if( $depth === 0 ) {
$parent = $root->children[] = new stdClass;
$parent->content = $content;
$depth++;
}
else if ( $depth++ > $maxDepth ) {
continue;
}
else {
if( !@$parent->children ) {
$parent->children = array();
}
$child = $parent->children[] = new stdClass;
$child->content = $content;
$child->parent = $parent;
$parent = $child;
}
}
else {
$depth--;
if( @$parent->parent ) {
$parent = $parent->parent;
}
if( @$content ) {
$parent->endContent = $content;
}
}
}
foreach( $root->children as $node ) {
$ret .= get_node_contents( $node );
}
$ret .= substr( $str, $index, $len - $index );
return $ret;
}
echo reduce_depth( "asdasdas[code]l[/code][code]a[code]lol[/code][code]b[code]c[code]d[code]e[code]f[code]g[/code][/code][/code][/code][/code][/code][/code]aasdasdsasd", 4 ). "
";
echo reduce_depth( "[code]a[code]b[code]c[code]d[code]e[code]f[code]g[/code][/code][/code][/code][/code][/code][/code]", 4 ) . "
";
echo reduce_depth( "[code]a[code]b[code]c[code]d[code]TEST[/code][code]e[code]f[code]g[/code][/code][/code][/code][/code][/code][/code]", 4 ) . "
";
echo reduce_depth("[code][code]bugi[/code]bugi2[/code]", 1) . "
";
echo reduce_depth("[code][code]bugi[/code]bugi2[code]bugi3[/code]bugi4[code]bugi5[/code]bugi6[/code]", 3) . "
";
/*
asdasdas[code]l[/code][code]a[code]lol[/code][code]b[code]c[code]d[code]e[/code][/code][/code][/code][/code]aasdasdsasd
[code]a[code]b[code]c[code]d[code]e[/code][/code][/code][/code][/code]
[code]a[code]b[code]c[code]d[code]TEST[/code][code]e[/code][/code][/code][/code][/code]
[code][code]bugi[/code]bugi2[/code]
[code][code]bugi[/code][code]bugi3[/code][code]bugi5[/code]bugi6[/code]
*/
I don't know what you're going for here, but if you're outputting this as HTML, you can just add this rule to your stylesheet:
test test test test test { display: none; }
Obviously, it'll have to be a real element, since <test>
isn't part of html.
It looks like you can use JBBCode:
http://jbbcode.com/docs#definingNewCodes
addBBCode's fifth and last parameter is a nest limit. By default
the nest limit is -1, meaning no limit. Nest limits allow you to
define a bbcode such that if the bbcode is embedded multiple times,
elements nested beyond the nest limit will be omitted from the output.