Быстрый jS парсер BB-кодов (на "лету")
100Кб парсит менее чем за 200ms (реальные BB-коды пользователя - значительно быстрее, ибо тестировал на тегах с ошибками)
<script type="text/javascript">
//Объект с функциями обработки тегов
var Fn = {
/*Служебные*/
none : function(tag, attr, content) {return 'µ'+tag+(attr?'='+attr:'')+']'+content+'[/'+tag+']';},
validAttr : function(attr) {return !(/[\n"<>\[\]]/.test(attr));},
parseAttr : function(attr) {return (attr? attr.replace(/^"(.*?)"$/,'$1'):'');},
attrTest : function(tag,attr) {/*Тесты Атрибутов*/},
b : function(tag, attr, content) {return (attr? Fn.none(tag, attr, content): '<strong>'+content+'</strong>');},
i : function(tag, attr, content) {return (attr? Fn.none(tag, attr, content): '<span style="font-style: italic;">'+content+'</span>');},
u : function(tag, attr, content) {return (attr? Fn.none(tag, attr, content): '<em class="bbuline">'+content+'</em>');},
s : function(tag, attr, content) {return (attr? Fn.none(tag, attr, content): '<del>'+content+'</del>');},
sup : function(tag, attr, content) {return (attr? Fn.none(tag, attr, content): '<sup>'+content+'</sup>');},
sub : function(tag, attr, content) {return (attr? Fn.none(tag, attr, content): '<sub>'+content+'</sub>');},
mark : function(tag, attr, content) {return (attr? Fn.none(tag, attr, content): '<span class="highlight-text">'+content+'</span>');},
font : function(tag, attr, content) {return '<span style="font-family: ' + attr + ';">' + content + '</span>';},
size : function(tag, attr, content) {return '<span style="font-size: ' + attr + ';">' + content + '</span>';},
color : function(tag, attr, content) {return '<span style="color: ' + attr + ';">' + content + '</span>';},
align : function(tag, attr, content) {return '<span style="display: block; text-align: ' + attr + ';">' + content + '</span>';},
url : function(tag, attr, content) {return (!attr? '<a href="' + content + '">' + content + '</a>' : '<a href="' + attr + '">' + content + '</a>');},
img : function(tag, attr, content) {return '<img src="' + content + '" class="postimg"/>';},
video : function(tag, attr, content) {return '<iframe width="480" height="284" src="'+ content +'" frameborder="0" allowfullscreen=""></iframe>';},
abbr : function(tag, attr, content) {return '<abbr title="' + attr + '">' + content + '</abbr>';},
quote : function(tag, attr, content) {return ((attr=Fn.parseAttr(attr))?'<quote title="' + attr + '">' + content + '</quote>':'<quote>' + content + '</quote>');}
};
eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('Z 1j(v,s,o){6 t={},p=/[\\n¬µ]/1e,n=/\\[([^\\[\\]]*?\\[)/g,l=/(\\][^\\[\\]]*?)\\]/g,k=/\\[([^\\]]*)\\]([^\\[]*)/g,h=/(\\/)?([a-z]+)?(?:=([^\\[\\]]+))?/,f=/\\[([^\\]]{2})([^\\[\\]]+)\\]\\[\\/\\1([^\\[\\]]+)\\]/g,d=/\\[\\/?[x-z].([^\\]]+)\\]/,c=/^(.*?\\[[^\\[\\]]{2}([^\\]]+)\\])\\[\\/([^\\]]{2})([^\\[\\]]+)\\]/g,b=/\\[\\/?[x-z]./,u=/\\[[x-z][a-15-9]([a-15-9]+)\\]/g;t.o={"\\n":"<1p>","µ":"n","¬":"r;"};7(o){p=/\\n/1e}v=v.10(p,Z(i){8 t.o[i]});v=v.10(n,Z(r,i){8"µ"+i});v=v.10(l,Z(L,r,i){8 r+"¬"});t.16={};6 F=-1;t.4={};6 a=0;v="[1b]"+v;6 K,g,K,C,B,q,z,w,J;v=v.10(k,Z(L,r,i){J=1;r.10(h,Z(O,N,M,P){J=0;z=N;K=M.1k();C=P});7(J||!K||K.12>1s||z&&C){t.4[w]["R"]+="µ"+r+"¬";8""}7(!t.16[K]){B=(++F%1f+1q+19*1h(F/1f)).1i(19);t.16[K]=B}1d{B=t.16[K]}w=(a++).1i(19);t.4[w]={};t.4[w]["14"]=K;t.4[w]["18"]=C;t.4[w]["R"]=i;8("["+(z?z:"")+B+w+"]")});6 m=1m,A=v,E=0,I=A.12,j=1h(I/m)+(I%m?1:0);7(o==2){m=I;j=1}6 v="";1a(j--){v+=A.1l(E*m,m);E++;6 y=13,e=1;1a(y){y=1g;7(e==1){6 x="0",H=0,G=0;v=v.10(f,Z(Q,i,S,M,r){y=13;6 N=x,T=9+S.12+M.12;7(r>H+G+3){x=N=v.11(v.1c("[",r-1),r).10(d,"$1")}H=r;G=T;6 U=t.4[S]["14"],P=t.4[S]["18"],O=t.4[S]["R"];7(s.17&&s.17[U]){O=D(O)}7(s[U]){O=s[U](U,P,O)}1d{O=s.1b(U,P,O)}t.4[N]["R"]+=O+t.4[M]["R"];8""})}7(!y){e=2;v=v.10(c,Z(T,W,U,i,N){y=13;6 M=W.12,X=W.1c("["+i);7(X<0){t.4[U]["R"]+="µ/"+t.4[N]["14"]+"]"+t.4[N]["R"];8 W}6 r=W.11(W.1c("[",X-1),X-1),O=r.10(b,""),S=T.11(X,M),V=S.1o("]")+1,Q=S.11(V),U=S.11(3,V-1),Y=t.4[U]["14"],P=t.4[U]["18"];Q=t.4[U]["R"]+Q;7(s.17&&s.17[Y]){Q=D(Q)}7(s[Y]){Q=s[Y](Y,P,Q)}1d{Q=s.1b(Y,P,Q)}t.4[O]["R"]+=Q+t.4[N]["R"];8 T.11(0,X)})}}}Z D(L){6 i=13;6 r=/\\[[x-z][a-15-9]([a-15-9]+)\\]/g;1a(i){i=1g;L=L.10(r,Z(O,N){i=13;6 M=t.4[N]["18"];8"["+t.4[N]["14"]+(M?"="+M:"")+"]"+t.4[N]["R"]})}8 L}v=D(t.4["0"]["R"]+v.11(5));v=v.10(/[µ¬]/g,Z(i){8(i=="µ"?"[":"]")});8 v};',62,91,'||||Tgx||var|if|return|||||||||||||||||||||||||||||||||||||||||||||cntR||||||||function|replace|substring|length|true|tag|z0|Tags|ParentWrapper|attr|36|while|none|lastIndexOf|else|gim|26|false|parseInt|toString|parseBB|toLowerCase|substr|1536|181|indexOf|br|1198|172|23'.split('|'),0,{}));
// Тестовая строка
var text = '[quote="test3"]test [b]blah\n\ [i]tata[/i] blah[/b] param [quote="test"]d[quote="test2"]lalsd[li]fnsdf[alalsdfsda qweqweqwe [u][u][u]te[/quote]r[u]tet[/u]er[/u][/u][/u] hjf [u]sdhg[/u] en[/quote]dtest [b]blah\n\ [i]tata[/i] blah[/b] param [quote="test"]d[quote="test2"]lalsd[li]fnsdf[alalsdfsda qweqweqwe [u][u][u]te[/quote]r[u]tet[/u]er[/u][/u][/u] hjf [u]sdhg[/u] en[/quote]dtest [b]blah\n\ [i]tata[/i] blah[/b] param [quote="test"]d[quote="test2"]lalsd[li]fnsdf[alalsdfsda qweqweqwe [u][u][u]te[/quote]r[u]tet[/u]er[/u][/u][/u] hjf [u]sdhg[/u] en[/quote]dtest [b]blah\n\ [i]tata[/i] blah[/b] param [quote="test"]d[quote="test2"]lalsd[li]fnsdf[alalsdfsda qweqweqwe [u][u][u]te[/quote]r[u]tet[/u]er[/u][/u][/u] hjf [u]sdhg[/u] en[/quote]dtest [b]blah\n\ [i]tata[/i] blah[/b] param [quote="test"]d[quote="test2"]lalsd[li]fnsdf[alalsdfsda qweqweqwe [u][u][u]te[/quote]r[u]tet[/u]er[/u][/u][/u] hjf [u]sdhg[/u] en[/quote]dtest [b]blah\n\ [i]tata[/i] blah[/b] param [quote="test"]d[quote="test2"]lalsd[li]fnsdf[alalsdfsda qweqweqwe [u][u][u]te[/quote]r[u]tet[/u]er[/u][/u][/u] hjf [u]sdhg[/u] en[/quote]dtest [b]blah\n\ [i]tata[/i] blah[/b] param [quote="test"]d[quote="test2"]lalsd[li]fnsdf[alalsdfsda qweqweqwe [u][u][u]te[/quote]r[u]tet[/u]er[/u][/u][/u] hjf [u]sdhg[/u] en[/quote]d\
[/quote]';
st = +new Date();
var out = parseBB (text,Fn);
var lng = out.length;
alert('Итог: '+(+new Date()-st)+', str.length='+lng +', '+ out );
</script>
В
Fn = {} прописываем свои функции обработки
При отсутствии тега в
Fn, - в строку возвращается исходный BB-код (через Fn.none )
Если теги не валидны - так же остаются их исходные BB-коды.
Функция делалась для предпросмотра "на лету" в форме ответа, при вводе символов
==================
PS: Если есть интерес, - тестируем, отписываемся