Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   Парсинг BBcode (https://javascript.ru/forum/misc/24939-parsing-bbcode.html)

trikadin 22.01.2012 19:31

Цитата:

Сообщение от Gozar
на скорости правда это не отразилось, может мало циклов,

Да и не должно было - тут же происходит каждый раз два переприсвоения в цикле) А в твоём варианте - только одно)

devote 23.01.2012 13:34

да, что-то более лучшего ничего не выходит, только так:

var text = 'test [b]blah [i]tata[/i] blah[/b] param [quote="test"]lal[alala[/quote] qweqweqwe [u]ter[u]tet[/u]er[/u] hjf [u]sdhg[/u] end';

var re = /(\[\s*([a-z]+)\s*(?:=?\s*([^\]]+))?\])([^\[]+)(\[\/\2\])/i,
    next = true, step = 1;

while( next ) {
    next = false;
    text = text.replace( re, function( all, tagattr, tag, attr, content, close ) {
        next = true;

        alert( [tagattr, tag, attr, content, close] );

        return '<' + tag + '>' + content + '</' + tag + '>';
    });
    if ( !next && step++ == 1 ) {
        next = true;
        re = /(\[\s*([a-z]+)\s*(?:=?\s*([^\]]+))?\])(.*?)(\[\/\2\])/i;
    }
}

alert( text );

Deff 05.01.2016 01:37

var text = 'test [b]blah\n\ [i]tata[/i] blah[/b] param [quote="test"]d[quote="test2"]lalsd[li]fnsdf[alalsdfsda[/quote] qweqweqwe [u]ter[u]t[/quote]et[/u]er[/u] hjf [u]sdhg[/u] end';

var chang = '¬'; //Строка замены для "["
var re = /(\[([a-z]+)(?:="?([^\]]+?))?"?\])([^\[]*)(\[\/\2\])/gi,
    next = true, step = 1;

while( next ) {
    next = false;
    if(step==1)text = text.replace( re, function( all, tagattr, tag, attr, content, close ) {
        next = true;

        //alert( [step,tagattr, tag, attr, content, close] );

        return '<' + tag + '>' + content + '</' + tag + '>';
    });
    if ( !next) {step = 2;
        text = text.replace(/^([\s\S]*?)(\[\/([a-z]+)\])([\s\S]*)$/i, function(str,strST,tagEnd, tag, strEnd) {
           next = true;
           var end = strST.length,
           st = strST.lastIndexOf('['+tag);
           if(st<0) return strST + chang+'/'+ tag + ']' + strEnd;

           var find = text.substring(st,end),
           rega = '^\\['+tag+'(?:="?([^\\[\\]]+?))?"?\\]([\\s\\S]*)$';

           var found = find.replace(RegExp(rega,'i'), function(str,attr,content) {return '<'+tag+'>'+ content.replace(/\[/g, chang) + '</'+tag+'>'});

           return text.substr(0,st) + (found!=find ? found : chang + find.slice(1)+ tagEnd) + strEnd;

      })
   }
}

text = text.replace(RegExp(chang,'g'),'['); //возвращаем скобку;
alert( text );


Чуть ускорил, сделав первый проход глобальным поиском (/gi),
На Втором проверка неполных вложенных тегов (Исключаем ситуации типа [div][li][/div][/li]; подменяем у них символ \[)
===================
В принципе вторая часть работает и самостоятельно, но совместно с первой, получаем приличное ускорение на тегах без квадратных скобок внутри

trikadin 05.01.2016 21:11

Deff, ты его четыре года писал? :D

Яростный Меч 05.01.2016 21:29

Понимаю что тема старая :)
но раз уж всплыла, то вот мой вариант. Здесь в упрощенном виде, только самые простые теги, чтобы нагляднее была идея. А идея вот в чем: когда натыкаемся на открывающий тег, кладем его в стек. Если встретили закрывающий, то проверяем его соответствие верхушке стека, если не соответствует, оставляем бб-код, иначе ставим закрывающий и убираем со стека. В конце, если что-то осталось на стеке, добиваем "закрывашками".

var parseBB = function(str) {
    if (!str) { return str; }
    var rx = /\[(\/?)(b|i|u|s)\s*\]/gi;
    var stack = [];
    str = str.replace(rx, function(m, close, tag) {
        tag = tag.toLowerCase();
        if (close) {
            if (!stack.length || (stack[stack.length - 1] !== tag)) {
                return m;
            }
            stack.pop();
        } else {
            stack.push(tag);
        }
        return "<" + close + tag + ">";
    });
    if (stack.length) {
        str = str + stack.reverse().map(function(tag) { 
            return "</" + tag + ">";
        }).join("");
    }
    return str;
};

Deff 07.01.2016 01:43

trikadin,
Нет, у мну 4 дня назад встала тема быстрого предпросмотра сообщений в топике(точнее мгновенного, по мере ввода), поискал в инете, наткнулся на эту тему, остальные Варианты были хуже

Deff 07.01.2016 01:46

Цитата:

Сообщение от Яростный Меч
иначе ставим закрывающий и убираем со стека. В конце, если что-то осталось на стеке, добиваем "закрывашками".

У мну лучше, 1. Решена проблема пересекающихся(или неполных) тегов
2. Задача по топику была делать не рекурсией(кушает много памяти при длинных строках с много тегами), а простым повтором через while
3. Нун вначале искать первый тег закрытия от начала строки и двигаться вверх до его "открывашки", только тогда не будет пересекающихся тегов(или конфликтов), если вдобавок на всём пути, пройденного до найденной "открывашки", убиваем(подменяем, с возвратом в конце распарса) все открывающиеся скобки "[" , ибо внутри не может быть валидных вложенных ВВ-тегов по определению.
Если "открывашка" не найдена, убиваем открывающуюся скобку "[" у найденного первоначального тега-"закрывашки" .
Крутим цикл пока не будут найдены все('ближайшие от начала') "закрывашки" ...

Deff 07.01.2016 03:01

Яростный Меч,
Тест: (тег [quote="test2"] - валидный - пропущен, по идее валидный и первый, но тут можно оспорить, ты сделал валидными теги [u]
var parseBB = function(str) {
    if (!str) { return str; }
    var rx = /\[(\/?)(b|i|u|s)\s*\]/gi;
    var stack = [];
    str = str.replace(rx, function(m, close, tag) {
        tag = tag.toLowerCase();
        if (close) {
            if (!stack.length || (stack[stack.length - 1] !== tag)) {
                return m;
            }
            stack.pop();
        } else {
            stack.push(tag);
        }
        return "<" + close + tag + ">";
    });
    if (stack.length) {
        str = str + stack.reverse().map(function(tag) { 
            return "</" + tag + ">";
        }).join("");
    }
    return str;
};
var text = 'test [b]blah\n\ [i]tata[/i] blah[/b] param [quote="test"]d[quote="test2"]lalsd[li]fnsdf[alalsdfsda[/quote] qweqweqwe [u]ter[u]t[/quote]et[/u]er[/u] hjf [u]sdhg[/u] end';
alert(parseBB(text));
//Убрал атрибуты, сменил quote на s //Да, тут терпимо, но: у [/s] - концовка осталась (ошибки в закрывашках критичны - цитата - тег <div> убила бы страницу)
var text2 = 'test [b]blah\n\ [i]tata[/i] blah[/b] param [s]d[s]lalsd[li]fnsdf[alalsdfsda[/s] qweqweqwe [u]ter[u]t[/s]et[/u]er[/u] hjf [u]sdhg[/u] end';
alert(parseBB(text2))

Вдобавок у меня, при парсе на лету, когда юзер не закончил строку, желателен максимальный распарс тегов
//Тут ксать у мну и таблицы еще есть, пока не додумал как парсить исключения-ошибки отсутствия некоторых тегов)

Яростный Меч 07.01.2016 03:23

Цитата:

Сообщение от Deff (Сообщение 402843)
1. Решена проблема пересекающихся(или неполных) тегов

У меня тоже решена, правда, на скорую руку примитивным способом, но тут можно допилить работу со стеком, и сделать по нормальному, не меняя общий подход. Не получится только игнорировать открывающий тег, для которого нет закрывашки, т.к. нет заглядывания вперед.

Цитата:

Сообщение от Deff (Сообщение 402843)
2. Задача по топику была делать не рекурсией(кушает много памяти при длинных строках с много тегами), а простым повтором через while

В моём случае всё делается за один replace. Т.е. по затратам памяти имеем только исходную строку и результат.


----
На форумах бывает тег оформления исходного кода, в котором теги [b] и т.п. вообще не заменяются. Твой способ сумеет такое поддержать? Мой - запросто, если при нахождении такого тега включать специальный режим "незамены".

Deff 07.01.2016 03:41

Яростный Меч,
Ну идея была такая: вкладывать в тег перепарсенной "открывашки" атрибут data-исходник в котором прописывать исходный код полного bb-teга в еncode, ибо парсятся все (а у меня есть и таблицы) если какой то тег в табле отсутствует, то нун возвращать теги в BB-код, что при JQ делается парой строк
На самом деле будут возвращаться все(до распарса в HTML), не прописанные в объекте перепарса (это на этапе самого распарса, не стал усложнять код незначимыми подробностями) Ибо у меня много кодов трансформируемых в несколько тегов и вставкой атрибутов
Вот эта функция будет браться из объекта с описанными функциями распарса по тегам
var found = find.replace(RegExp(rega,'i'), function(str,attr,content) {return '<'+tag+'>'+ content.replace(/\[/g, chang) + '</'+tag+'>'});

laimas 07.01.2016 03:57

Цитата:

Сообщение от Яростный Меч
У меня тоже решена, правда, на скорую руку примитивным способом, но тут можно допилить работу со стеком, и сделать по нормальному, не меняя общий подход. Не получится только игнорировать открывающий тег, для которого нет закрывашки, т.к. нет заглядывания вперед.

Нужно описать правила, без них не получится, это непарные теги, например IMG, это вложения для таблиц и списков, если таковые теги разрешены, и т.п.

Deff 07.01.2016 04:06

laimas,
Однотеговых BB-кодов мало <br> <img> [you] (часто есть - имя юзера)
Они парсятся первыми, замечание справедливое, но я описал, что выходная функция HTML тегов должна быть в итоге привязана к объекту выходных функций по тегам, ибо часто теги преобразуются в многотеговые конструкции HTML
Опять же и атрибуты меняют итоговый код HTML

laimas 07.01.2016 04:21

Цитата:

Сообщение от Deff
Однотеговых BB-кодов мало <br> <img> [you] (часто есть - имя юзера)

Ну так они есть :) Использование принципа работы стека, это старая и удобная идея для таковых разборов, и без правил не получится, ну если только разрешено использование простейших html-тегов.

Deff 07.01.2016 04:26

laimas,
Вообще тема интересная, рыл тут четыре дня, вот лучший пост был этот от devote (Были пару интересных импортных постов, но там код для анализа ошибок на страницу
Думаю в принципе, задача поиска без ошибок без движения челноком по строке (ищем закрывашку и идём от нёё вверх к открывашке) решается весьма трудоёмко. Пока реальных кодов с учётом всех ошибок мизер..

laimas 07.01.2016 04:36

Да, были темы на форуме по использованию принципа стека, правда не в контексте ВВ, но суть та же.

Цитата:

Сообщение от Deff
Думаю в принципе, задача поиска без ошибок без движения челноком по строке

Ну как сказать, ведь и браузеру нужно переварить строку содержащую html-код, и он тоже поступит так же, но и обязательно по правилам. При этом есть "любезые" браузеры закрывающие тег, если допущена ошибка, а есть и не делающие такой медвежей услуги. Например, под FF видно, что-то не то, а причины не понять, а оплеванный ослик в своем отладчике сразу показал ошибку, ибо он не закрыл тег за нерадивым исполнителем. )

Если подумать, то думаю можно использовать стек и как источник "места" ошибок, делать откат и удалять некорректное.

Deff 07.01.2016 04:40

laimas,
Ну в итоге, совместно с куском от dеvote мой скрипт парсит быстее - проверил на мегабайте BB-кодов (Правдо мало вставлял лишних квадратных скобок, спецом ошибок в BB-кодах 20% (если интересно завтра выложу тест

laimas 07.01.2016 04:44

Выкладывайте, правда ВВ код можно обработать и на сервере, и для этого есть готовое на Cи. Я не сторонник взваливать все на клиента. )

Deff 07.01.2016 04:48

laimas,
Тут идея скрытого текста небольших сообщений обмена между "маффами", поскольку после кодирования(при отправке) и скрытия сообщения уже не прочесть(ессенно и серв не парсит кодированное) (а общение через личку - сильно много телодвижений, а тут видит конкретный чел) Обычно играют в чате - но уменя все чаты сторонние, и там тож личка - долгая песня, и не видно всех сообщений, а в форуме сразу вся страница и скрытое-невидимое остальным, меж общим кругом общения

Яростный Меч 07.01.2016 05:10

Вопрос: вот такая строка во что должна превращаться?
1[b]2[u]3[/b]4[/u]5


в идеале, как мне кажется, "1<b>2<u>3</u></b><u>4</u>5"

по крайней мере на этом форуме именно так работает

laimas 07.01.2016 05:13

Цитата:

Сообщение от Яростный Меч
Вопрос: вот такая строка во что должна превращаться?
12345

Здесь ошибка вложения, и по хорошему нужно игнорировать такое, а не догадываться чего хотят и исправлять.

Яростный Меч 07.01.2016 05:20

Цитата:

Сообщение от laimas (Сообщение 402863)
Здесь ошибка вложения, и по хорошему нужно игнорировать такое, а не догадываться чего хотят и исправлять.

но с логической т.з. всё вроде правильно, 2 только болд, 4 подчеркнуто, 3 на пересечении.

на форуме sql.ru то же самое, щас проверил

laimas 07.01.2016 05:24

Нет не правильно, и не с точки зрения логики, а правилами определенными.

Deff 07.01.2016 05:46

:) Ну главное - идеи - идея неплоха, но нет алгоритма поиска ошибок
И проверил на больших массивах кой код, совместно с куском от devote шустрее, именно он парсит теги без проблем в один -два прохода (без всяки массивов и реверса

Deff 07.01.2016 05:46

:) Ну главное - идеи - идея неплоха, но нет алгоритма поиска ошибок
И проверил на больших массивах свой код, совместно с куском от devote шустрее, именно он парсит теги без проблем в один -два прохода (без всяки массивов и реверса Завтра выложу рандом - ибо лень мегабайты вставлять в песочню

laimas 07.01.2016 05:56

Цитата:

Сообщение от Deff
Ну главное - идеи - идея неплоха, но нет алгоритма поиска ошибок

Это как посмотреть на идею. Нашли открывающий тег, помещаем его в стек:

1) если его нет в правилах описанных, значит далее может идти текст или другой открывающий тег
2) если тег есть в правилах, проверяем что следует за ним и что может следовать за ним согласно правил, соответственно следствие

нашли закрывающий тег:

1) если есть правила описанные для тега, проверяем корректно ли закрытие, и если нет, очищаем вершину стека, а текст помещаем как есть
2) если тега нет в правилах, закрытие корректное, обрамляем текст htnl-тегом, иначе ошибка и игнорируем, помещая текст как есть
3) очищаем вершину стека

Deff 07.01.2016 06:01

laimas,
Плюнь пока на правила для тега, это тоже легко поправимо, поставив регу от devote вместо фиксированного списка и объект с функцией перепарса по tag
Воть ошибки, что принимать за корректное - а что нет - тут проблемы - ибо зависит от положения найденного тега, что за один проход вряд ли сделаешь (ну нашли, а внутри несколько вложенных валидных, или не валидных, т.е нун считать кратность вложенных идентичных - как минимум

laimas 07.01.2016 06:06

Цитата:

Сообщение от Deff
ибо зависит от положения найденного тега, что за один проход вряд ли сделаешь

Вершина стека и определяет валидно или нет, ваша задача следить за вершиной стека.

Deff 07.01.2016 06:20

laimas,
Проще выложи код завтра, а я тест на скорость, ибо один фиг валидация затруднена (мну перерыл кучу, со стеком тож видел)
Самый короткий и простой метод с рекурсией(идём от обрамляющих тегов к вложенным), автоматом поддерживает валидность за счёт сокращения вложенной строки - но рекурсия

laimas 07.01.2016 11:10

Цитата:

Сообщение от Deff
Проще выложи код завтра

Код чего, готового разбора по принципу стека? У меня его нет, но то что можно сделать такое, это 100% гарантии. Вряд ли бы я стал тужится с разбором ВВ только лишь рег. выражениями на JS, хотя бы уже потому, что RegExp в нем хилый по набору, в отличие от возможностей сервера.

Кроме это, "искать возможные ошибки посредством повторных разборов строки", это накладно, гораздо проще смещаться по массиву. И хотите вы того или нет, но html это разнобразие тегов, и без правил не обойтись, вряд ли длинные портяки шаблонов рег. выражений для решения данного условия, это будет легко для RegExp.

Я согласен, что простейший набор, типа как тут B, I, U, ... вполне можно обработать и RegExp, но при ошибках вложений все равно придется карячится.

Стек же есть стек, если был опыт работы с ассемблером, то возможно и сталкивались с очень интересными решениями как раз используя стек, где вроде бы о нем и речи быть не должно. В РНР к примеру, в SPL, есть реализация стека.

Я никого не принуждаю, как считаете нужным, так и делайте. Главная цель скорость, а остальное боком, ну так пожалуйста. Я же, для себя, подобное бы делал (буду, если потребуется) именно на стеке.

Яростный Меч 07.01.2016 13:54

Deff,

так что вот с этим? http://javascript.ru/forum/misc/2493...tml#post402862

с точки зрения знатока html это невалидный кейс, а для "человека обыкновенного" - просто пересечение областей.
Чтобы сравнивать скорости и подходы, надо определиться с подобными случаями.

Яростный Меч 07.01.2016 14:01

Цитата:

Сообщение от laimas
Я же, для себя, подобное бы делал (буду, если потребуется) именно на стеке.

"стек и единственный реплейс" в принципе могут всё, кроме игнорирования одиночных открывающих тегов. Чтобы это добавить, надо сделать предварительный обход текста с выяснением, какие по счету встретившиеся открывающие теги проигнорировать при замене.

Зато, как я уже говорил, есть потенциальные возможности добавить тег вроде [src] (вроде местного [js]), в которых содержится код и в которых не заменяются прочие теги.

laimas 07.01.2016 14:20

Цитата:

Сообщение от Яростный Меч
Чтобы это добавить, надо сделать предварительный обход текста с выяснением, какие по счету встретившиеся открывающие теги проигнорировать при замене.

Смотря какой тег с ошибкой, совсем не обязательно потребуется что-то выяснять. Еще раз - html код, это всегда сначала открывающий тег (о не парных тегах пока молчим), именно он и только он помещается в стек. Закрывающий тег не помещается в стек, он не нужен там, этот тег для контроля.
В случае вашего невалидного кода b -> u -> /b -> /u:

1) открывающий тег b в стек, далее может идти либо закрывающий тег b, любо возможный в таком наборе иной открывающий тег
2) открывающий тег u в стек, далее может идти либо закрывающий тег u, любо возможный в таком наборе иной иной открывающий тег
3) закрывающий тег b, сравниваем его с вершиной стека, а в ней u - ошибка, удаляем из вершины стека u, текст обрамляющий этим невалидным набором на вывод как есть
4) закрывающий тег u, сравниваем его с вершиной стека, а в ней b - ошибка, удаляем из вершины стека b, текст обрамляющий этим невалидным набором на вывод как есть

С тегами более сложными, такими как списки, таблицы... В списках по алгоритму указанному выше будут удаляться дочерние элементы, если только в них ошибка, не закрыты к примеру, тоже самое и с таблицами, удаление некорректных ячеек. Только в этом случае нельзя бросить текст просто так между tr и td, а значит нужно анализировать где ошибка, есть ли текст предшествующий, и если есть спускаться по стеку вниз до родительского элемента table - это будет вершина стека до которой нужно выбросить некорректные вложения.

Deff 12.01.2016 20:39

Быстрый 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>","µ":"&#1n","¬":"&#1r;"};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: Если есть интерес, - тестируем, отписываемся

mat_ppc 20.09.2016 17:34

VM17787:1 Uncaught TypeError: Cannot read property 'toLowerCase' of undefined

Строка: ['URL=https://imgdepo.com/show/9759621]['IMG]http://imgdepo.com/thumb/2016/Sep/20/85264af7.jpg[/IMG'][/URL']


Часовой пояс GMT +3, время: 23:36.