I'm looking for a way to properly replace nested custom tags with their HTML equivalents. For example, suppose we have the following text:
This is {b:bold text}
Which should become:
This is <b>bold text</b>
I'm aware that I can - and probably should - use something like a span with a "bold" class instead of the old "b" tags, but there's a reason I'm sticking with "b" for the purpose of this example. I may have nested tags:
This is {b:bold text and {i:italic}}
which should become:
This is <b>bold text and <i>italic</i></b>
However, I have these regexes (which I use with the replace() function):
/\{b:([\s\S]*?)\}/gm
/\{i:([\s\S]*?)\}/gm
And then the result will become:
This is <b>bold text and <i>italic</b></i>
The tags are not properly nested. Again, using spans can solve this in this case, but that won't work with things like "ul", "li", "h1", ... Greedy regexes will also cause problems if the text looks like this:
This is {b:bold text} and {i:italic}
So my current solution is to replace everything with span first, using a data-tag attribute to indicate what it should actually be, and then use jQuery to find all span nodes and replace them with the proper tags:
{h:This is a header}
becomes
<span data-tag='h1'>This is a header</span>
becomes
<h1>This is a header</h1>
It works well, but i'm wondering if there is an easier way to do this. The intermediate method feels a bit like a duct tape solution and I would like to "beautify" it.
Any suggestions?
A simple stack goes a long way
function doReplace( str ) {
var stack = [],
ret = [],
ch;
for( var i = 0, l = str.length; i < l; ++i ) {
var ch = str.charAt(i);
if( ch === "{" ) {
var pos = str.indexOf( ":", i+1);
if( pos < 0 ) {
throw new SyntaxError();
}
var tagName = str.substring( i + 1, pos);
if( /[^A-Za-z0-9]/.test(tagName)) {
throw new SyntaxError();
}
ret.push( "<" + tagName + ">" );
stack.push( tagName);
i+= tagName.length + 1;
}
else if( ch === "}" ) {
if( !stack.length ) {
throw new SyntaxError();
}
var tagName = stack.pop();
ret.push( "</" + tagName + ">" );
}
else {
ret.push( ch );
}
}
if( stack.length ) {
throw new SyntaxError();
}
return ret.join("");
}
doReplace( "This is {b:bold text {i:italic text{i:italic text{i:italic text{i:italic text{i:italic text{i:italic text}}}}}}}")
//"This is <b>bold text <i>italic text<i>italic text<i>italic text<i>italic text<i>italic text<i>italic text</i></i></i></i></i></i></b>"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With