0

I want to do form validation at user side with JavaScript (jQuery is also used). The goal is to remove nested bbCode [quote] tags deeper than level 2. Say, we have this text:

[quote=SoundMAX][quote=Laplundik][quote=SoundMAX]
blahblahblah[/quote]
blahblah
[/quote]
blah[/quote]

And get this:

[quote=SoundMAX][quote=Laplundik]
blahblah
[/quote]
blah[/quote]

My only idea is to .replace [quote] with <div>, then create DOM object and remove anything deeper than 2 with jQuery, and parse all backwards to bbCode. But that solution seems too complicated, are there more elegant one?

EDIT:

Thanks for nice solutions. Based on darioo's answer, I did this:

var text=$('#edit-privatemsgbody').val();
var tmp=[];
var level=0;

for (var i=0,l=text.length;i<l;i++){
 if(text[i]=='['&&text[i+1]=='q') level++; 
 if(text[i-6]=='q'&&text[i-7]=='/'&&text[i-8]=='[') level--;
 if(level<3) tmp.push(text[i]);
}
alert(tmp.join(''));

Which works just fine.

But idealmachine's solution was like a flash. I didn't know about replace callback function parameters before, now that is handy! I'll settle with it.

2 Answers2

2

Actually, you can use regex if you look at it as a limited tool that cannot handle the nesting itself. The .replace string method can call a function to find the replacement text for each match, which allows us to track how deep we are in the markup structure (code also posted at http://jsfiddle.net/Zbgr3/3/):

var quoteLevel = 0;

alert(s.replace(/\[(\/?)quote[^\]]*\]|./gi, function(tag, slash) {
    // Opening tag?
    if(tag.length > 1 && !slash.length) quoteLevel += 1;
    // What to strip
    var strip = quoteLevel > 2;
    // Closing tag?
    if(tag.length > 1 && slash.length) quoteLevel -= 1;

    if(strip) return '';
    return tag;
}));

If you want some tolerance for errors in the markup, you could add some extra code that, for example, prevents quoteLevel from falling below zero.

PleaseStand
  • 31,641
  • 6
  • 68
  • 95
1

Use a regular array as a stack. Every time you encounter [quote], increase your array by one using its push() method. When you encounter [/quote], decrease your array by one using its pop() method.

If you encounter [quote] and your array length is 2, remove that [quote], and remove the next [/quote] you encounter.

If you don't have the same number of open and closed quotes, then you'll have to handle that in a way you find appropriate.

darioo
  • 46,442
  • 10
  • 75
  • 103