Javascript не анализира вложен Bbcode

Кодирах Javascript bbcode, подобен на този, който използвам, за да напиша това съобщение. Той също така включва поле за визуализация на живо като това, което виждам по-долу. Единственият проблем, с който се сблъсквам в момента, е, че някои вложени bbcode не се анализират.

Например:

[quote]
   [quote][/quote]
[/quote]

Не се анализира правилно.

Това е моят Javascript в момента.

function preview() {

    var txt = $('#editor').val();
    txt = txt.replace(/</g,'&lt;');
    txt = txt.replace(/>/g,'&gt;');

    txt = txt.replace(/[\r\n]/g,'%lb%');

    var find    = [
                   /\[quote\](.*?)\[\/quote\]/gi,
                   /\[quote author="(.*?)" date="(.*?)"\](.*?)\[\/quote\]/gi,
                   /\[b\](.*?)\[\/b\]/gi,
                   /\[i\](.*?)\[\/i\]/gi,
                   /\[u\](.*?)\[\/u\]/gi,
                   /\[left\](.*?)\[\/left\]/gi,
                   /\[center\](.*?)\[\/center\]/gi,
                   /\[right\](.*?)\[\/right\]/gi,
                   /\[size=(10|12|24|30)](.*?)\[\/size\]/gi,
                   /\[font=(.*?)](.*?)\[\/font\]/gi,
                   /\[color=(.*?)](.*?)\[\/color\]/gi,
                   /\[url(?:\=?)(.*?)\](.*?)\[\/url\]/gi,
                   /\[email=(.*?)\](.*?)\[\/email\]/gi,
                   /\[email\](.*?)\[\/email\]/gi,
                   /\[img(.*?)\](.*?)\[\/img\]/gi,
                   /(?:%lb%|\s)*\[code(?:\=?)(?:.*?)\](?:%lb%|\s)*(.*?)(?:%lb%|\s)*\[\/code\](?:%lb%|\s)*/gi,

                   /\[list(.*?)\](.*?)\[\*\](.*?)(?:%lb%|\s)*(\[\*\].*?\[\/list\]|\[\/list\])/i,
                   /(?:%lb%|\s)*\[list\](?:%lb%|\s)*(.*?)(?:%lb%|\s)*\[\/list\](?:%lb%|\s)*/gi,
                   /(?:%lb%|\s)*\[list=(\d)\](?:%lb%|\s)*(.*?)(?:%lb%|\s)*\[\/list\](?:%lb%|\s)*/gi,
                   /(?:%lb%){3,}/g

                   ];
    var replace = [
                   '<blockquote><div class="quote"><div class="quote_body">$1</div></div></blockquote>',
                   '<blockquote><div class="quote"><div class="quote_author"><span class="quote_from">Quote from</span> <span class="author">$1</span> on <span class="date">$2</span></div><div class="quote_body">$3</div></div></blockquote>',
                   '<b>$1<\/b>',
                   '<i>$1<\/i>',
                   '<u>$1<\/u>',
                   '<div class="align_left">$1<\/div>',
                   '<div class="align_center">$1<\/div>',
                   '<div class="align_right">$1<\/div>',
                   '<span style="font-size:$1px;">$2</span>',
                   '<span style="font-family:$1;">$2</span>',
                   '<span style="color:$1;">$2</span>',
                   '<a href="/bg$1">$2</a>',
                   '<a href="/bgmailto:$1">$2</a>',
                   '<a href="/bgmailto:$1">$1</a>',                   
                   '<img $1 src="$2" />',
                   '<pre><code>$1</code></pre>',
                   '[list$1]$2<li>$3</li>$4',
                   '<ul>$1</ul>',
                   '<ol start=$1>$2</ol>',
                   '%lb%%lb%'

                   ];

    // fix [*] so that they only work inside [/list]
    for(var i in find)
    {
        txt = txt.replace(find[i],replace[i]);
        if(i == 17) while(txt.match(find[i],replace[i])) txt = txt.replace(find[i],replace[i]);
    }

    // Fix Smilies
    txt = txt.replace(/%lb%/g,'<br />');
    txt = txt.replace(/\:\)/g, '<img class="smiley" src="/img/smilies/smile.gif">');
    txt = txt.replace(/\:-\)/g, '<img class="smiley" src="/img/smilies/happy.gif">');
    txt = txt.replace(/\:D/g, '<img class="smiley" src="/img/smilies/biggrin.gif">');
    txt = txt.replace(/\:\(/g, '<img class="smiley" src="/img/smilies/sad.gif">');
    txt = txt.replace(/8\)/g, '<img class="smiley" src="/img/smilies/cool.gif">');
    txt = txt.replace(/=O/g, '<img class="smiley" src="/img/smilies/surprised.gif">');
    txt = txt.replace(/\:-\|\|/g, '<img class="smiley" src="/img/smilies/mad.gif">');
    txt = txt.replace(/\:P/g, '<img class="smiley" src="/img/smilies/stongue.gif">');
    txt = txt.replace(/\}\-\(/g, '<img class="smiley" src="/img/smilies/confused.gif">');

    // Format Dates
    txt = txt.replace(/\d{10}/g, function($0) {
        var d = new Date($0*1000);
        var months = new Array('January','February','March','April','May','June','July','August','September','October','November','December');
        return "" + months[d.getMonth()] + " " + d.getDate() + ", " + d.getFullYear() + ", " + (d.getHours()%12) + ":" + d.getMinutes() + " " + (d.getHours()<12 ? 'AM' : 'PM');
    });

    // Update the preview box
    $('.preview').html(txt);
}

Това обръща почти всички мои bbcode тагове. Етикетът за кавички е проблематичен, тъй като понякога не обръща вложените тагове за кавички или анализира съдържанието на вътрешните тагове за кавички.

Ако някой може да предложи решение ще съм много благодарен. Благодаря ти!


person Mark Anderson    schedule 10.03.2010    source източник
comment
Вашият BBCode не е нормален език и следователно не може да бъде анализиран с регулярен израз. Напишете парсер, който следи отворените и затворените тагове, за да намери съвпадащите двойки. С това можете дори да забележите синтактични грешки (грешно влагане, липсващ отварящ/затварящ етикет и т.н.).   -  person Gumbo    schedule 11.03.2010
comment
Същото важи и за HTML: stackoverflow.com/questions/1732348/   -  person Marcel Korpel    schedule 11.03.2010


Отговори (1)


Три решения:

  1. Напишете анализатор. Това ще доведе до най-доброто решение, но изисква нетривиално количество усилия.

  2. Намерете библиотека за анализ на BBCode. Вероятно толкова добър, колкото номер 1 по качество и значително по-лесен.

  3. Добавете отрицателен поглед напред във вътрешността на всеки регулярен израз на маркер и го прилагайте непрекъснато, докато няма съвпадение. напр.:

    \[quote\]((?:[^](?!\[quote\]))*?)\[\/quote\]
    

    Това ще улови вътрешния цитат, а след като бъде заменен, външния. Не е толкова чист като другите два, но вероятно най-бързото решение.

person Max Shawabkeh    schedule 10.03.2010
comment
Горещо препоръчвам #2: съществуваща библиотека вероятно ще бъде по-малко бъгова от вашата собствена, поне на първо място. - person Marcel Korpel; 11.03.2010