Эта тема на forum.dklab.ru


7.3.: Правильный парсинг BBCode
Начну с примера:
$text=ereg_replace("\\[b\\](.*)\\[/b\\]","<b>\\1</b>",$text);
То есть любой текст между тегами b в квадратных скобках заменить на их html-эквиваленты. Это все отлично работает:
[b]text[/b]
...заменится на...
<b>text</b>
однако
[b]text1[/b][b]text2[/b]
...заменяется почему-то на...
text1[/b][b]text2
Я подглядел вариант реализации того же самого в регулярных выражениях языка Перл (posix вроде) из скрипта форума yUAC:
"/\[b\](.*)\[\/b\]/isU" => "<b>\\1</b>"
То есть практически то же самое, может только /isU здесь что-то меняет. Разъясните ситуацию, пожалуйста. Желательно на языке RegExp.
Ant:
Разъясните ситуацию, пожалуйста. Желательно на языке RegExp.
Не знаю как в PHP, а в Perl есть понятие «жадности квантификатора». Как я понимаю, в Вашем случае дело именно в этом. Выражение «(.*)» «съедает» всё вплоть до последнего найденного объекта. Чтобы этого не происходило, в Perl, например, после * ставится знак вопроса (после чего квантификатор становится не жадным). См. документацию.
Дмитрий Котеров:

$text = str_replace("[b]", "<b>", $text);
$text = str_replace("[/b]", "</b>", $text);

7.3.:
Дмитрий Котеров:
Я так и сделал (уже давно).
Юрий Насретдинов:
только /isU здесь что-то меняет
i - ignore case - игнорировать регистр
s - воспринимать как одну строку
U - убирает "жадность" регов, т.е. в качестве (.*) он стремится теперь выбрать не максимальную строку, а минимальную
Дмитрий Эсс:
ИМХо вариант ДК самый правильный, т.к. он простой, и не возникнет проблем с вложенностью тегов.
Ant:


$text = str_replace("[b]", "<b>", $text);
$text = str_replace("[/b]", "</b>", $text);


ИМХо вариант ДК самый правильный, т.к. он простой, и не возникнет проблем с вложенностью тегов.
А если пользователь забудет закрыть тэг?
Дмитрий Котеров:
Значит, у него будет оставшийся текст весь жирный. Вот как у Вас в цитатах выше.
Ant:
Вот как у Вас в цитатах выше.
Я уже поправил.

Значит, у него будет оставшийся текст весь жирный.
Значит, надо всё-таки править по первому варианту, иначе, боюсь, будет не очень хорошо.
Дмитрий Котеров:
А Вы уверены, что первый вариант нельзя обмануть? Например,
......
Ant:
А Вы уверены, что первый вариант нельзя обмануть? Например,
Что-то я не понял, первый вариант преобразует только парные варианты (остальное останется не тронутым).

P.S. А куда девался confirm при запросе на удаление постинга?
Дмитрий Котеров:
Что-то я не понял
Вы все поняли. Это я ошибся.
7.3.:
Если дизайн настроен правильно через css, то даже незакрытые теги типа <b> ничего не испортят. В моем случае это именно так.
Юрий Насретдинов:
Дмитрий Котеров:
Этот вариант в некоторых случаях абсолютно непримемлем. Например чат, в котором есть BBCode. Если кто-то забудет закрыть тег <b>, то все полетит к чертовой матери. Я просто с таким уже встречался, и поэтому заменяю теперь BB-теги только регами. К тому же, во многих случаях для парсинга тегов просто не обойтись без регов (тот же тег ). Так что, честно говоря, Ваш вариант "катит" либо для несложных систем (с вложенными таблицами, и т.д.), либо для систем, в которых целостность сообщений не требуется. В любом случае это делать идеологически неправильно скажем для форума. Ведь например тег закрывается автоматически, но не остается открытым (наверное тогда просто таблицы нафиг полетят) ? Это без регов тоже не сделаешь...
Дмитрий Эсс:
yUAC:
Можно проверять количество открытых и закрытых тегов (http://www.php.net/substr_count) и добавлять в конце постинга нужное количество закрывающих тегов.
Юрий Насретдинов:
Можно проверять количество открытых и закрытых тегов (http://www.php.net/substr_count) и добавлять в конце постинга нужное количество закрывающих тегов.
Зачем мучаться, когда это можно сделать регами ? Тем более, PRCE работают очень даже быстро даже для мегабайтов текста !
Дмитрий Эсс:
yUAC:
Так ИМХО проще и нагляднее.
Юрий Насретдинов:
Дмитрий Эсс:
Регами или substr_count (кстати, не так давно узнал об этой функции, но не на этом форуме, правда) ?
Дмитрий Эсс:
Я про способ ДК.
Ant:
Ессно, регами всё проще делать. На то, собственно, они и были придуманы.
Юрий Насретдинов:
Дмитрий Эсс:
Ну не скажи. Для тех, для кого реги это не просто набор символов, и они хотя бы немного разбираются в регулярных выражениях, второй вариант является более наглядным.
Дмитрий Котеров:
yUAC:
Вообще-то, чтобы ничего не «летело», можно текст помещать в отдельную таблицу. Тогда даже незакрытый тэг <b> не страшен.
Дмитрий Эсс:
yUAC:
Это наезд? =) В регах я разбираюсь. Нагляднее и короче - это разные вещи.
Юрий Насретдинов:
Вообще-то, чтобы ничего не «летело», можно текст помещать в отдельную таблицу.
Обычно так все и делают. Но вот незакрытый тег "<table>", или, наоборот, лишний "</table>" может кардинаьно изменить вид сообщдений... Или даже "обрубленный" тег <img> (бывает при обилии смайликов) может убить всю таблицу нафиг... Хотя тут даже реги не помогут :).

Это наезд? =) В регах я разбираюсь.
Это было обращение не конкретно к тебе, а вообще к тем, кто пытается сделать систему BBCode ;)
Евгений Галашин:
ПХПББ сначала парсит на предмет наличия незакрытых/неверный тегов, к "правильным" добавляет uid и кладёт всё это в БД. при показе делается str_replace.
то есть:
old => old => <b>old</b>
*едит* блин, забыл ББкод отключить =)
Юрий Насретдинов:
zmeigorin:
Похоже... Только непонятно зачем это делать ?
Евгений Галашин:
yUAC:
как зачем? Дооолгий процесс парсинга выполняется один раз(при отправке), а при каждом показе - только быстрый srt_replace
Юрий Насретдинов:
Дооолгий процесс парсинга выполняется один раз(при отправке), а при каждом показе - только быстрый srt_replace
Доооолгий процесс парсинга выполняется только 1 раз при добавлении сообщения, а при каждом показе - только замена смайликов, BBCode уже "скомпилирован" в HTML.
Дмитрий Котеров:
Вот. кстати, прекрасный пример, как можно начинать извращаться, если элементарно не умеешь программировать. phpBB тому — живой пример. Люди и слыхом не слыхивали о такой технике, как кэширование, в результате полностью испаганили весь механизим парсинга bbcode.
Евгений Галашин:
yUAC:
а вот и нет. откройте БД и посмотрите.
Юрий Насретдинов:
zmeigorin:
Эээ, я вообще говоря описывал более "правильный" алгоритм, хотя конечно не скажу, что он самый лучший. Зато для вывода сообщений без возможности редактирования очень хорошо подходит :) (правда у меня есть редактирование сообщений, и для обратного преобразования тоже зачастую без регов не обойтись)
Дмитрий Эсс:
yUAC:
Редактирование - это редкий случай, можно и подождать доли секунды =).
Юрий Насретдинов:
Редактирование - это редкий случай, можно и подождать доли секунды =).
Дело даже не во времени "отпарсинга" сообщения (а оно невелико), а в "правильности" такого подхода - ведь структура BBCode может измениться, и тогда старые сообщения не будет возможности редактировать правильно. К тому же, если кому-то захочется изменить стиль , и изменится хотя бы чуть-чуть HTML-код, отвечающий за цитаты, то редактирование не станет возможным - пользователю вывалится HTML...
Дмитрий Эсс:
yUAC:
По идеологии это не правильно, согласнен. Хотя на практике это тоже решаемо. Можно преобразовать всё обратно в BBCode, изменить стиль и преобразовать назад.
Дмитрий Котеров:
Так не делают — если данные однажды превращены в конечное визуальное представление (шаблонизатор, HTML — да что угодно), то назад уже их не получить. Особенность слабоструктурированных данных такая.

Еще раз: бороться с малой производительностью следует методом кэширования, и никак иначе. Это единственный способ, который позволяет не портить исходные данные и в то же время добиться такой же скорости работы, которая была бы при их «порче».
Юрий Насретдинов:
Дмитрий Котеров:
Остается разве что излишнее дублирование данных ? ИМХО, если один раз написать полностью систему BBCode, и никогда её больше не переделывать, то можно обойтись без кэширования. То же самое, что как получить "нераскрашенный" код ? Наверное strip_tags ?
Дмитрий Котеров:
Сколько ж раз говорить, что кэширование — это не дублирование данных. Дублированием оно было бы, если бы потеря «дублированных» данных вела к неработоспособности системы, или если бы система не могла работать в отсутствии дубликата. Т.к. и то, и другое неверно, то никакое это не дублирование.
Юрий Насретдинов:
Т.к. и то, и другое неверно, то никакое это не дублирование.
Хм. Ну я имел ввиду "кэширование каждого сообщения", которое я понимаю под "дублированием".
P.S. И все-таки, как убирается "раскраска" из кодов PHP,Perl... ?
Дмитрий Котеров:
Что значит «как убирается«? Никак не убирается, раскрасили один раз — и все.
Евгений Галашин:
P.S. И все-таки, как убирается "раскраска" из кодов PHP,Perl... ?
судя по тому, что происходит при глюках, хранятся два текста - исходный и раскрашеный.
Дмитрий Котеров:
Естественно. Но второй — необязательный, и его можно в любой момент удалить — в таком случае он сгенерируется автоматом (при взведенном значении соответствующей константы — сейчас она для пущей скорости отключена, ибо в форуме много старых нераскрашенных исходников). Это и есть кэширование.
Юрий Насретдинов:
Дмитрий Котеров:
Во, теперь понятно. Конечно, как всегда, оно "перекрашивается" регами, да ? Похоже, этот форум уже не "вылечить" от тормозов... :)
Дмитрий Котеров:
Перекрашивается оно Colorerl-ом. В Готовых решениях есть библиотека для этого.
Юрий Насретдинов:
Дмитрий Котеров:
Я имел ввиду, то код "раскрашен", или нет, проверяется регами, я так понимаю ?

В Готовых решениях есть библиотека для этого
Вот, кстати. Я там так и не смог найти, в каком же файле сменять именно цвета раскраски, жирность текста, и т.д. Я только нашел, где менять саму структуру раскраски PHP-кода, а где цвета - то менять ? Она инклюдит в начале цветовую схема, а где она - непонятно.
Дмитрий Котеров:
Да нет, если кэш пуст — значит, не раскрашен. Если не пуст — значит, раскрашен. При чем тут реги?

Насчет colorer-а — читайте весь тот топик внимательно, там все написано.
Юрий Насретдинов:
При чем тут реги?
Ну, значит я ошибался...
Anonymous:
$realbody = preg_replace("#\(.*?)\#si", "<b>\\1</b>", $realbody);

если ещё кому интересно, то делать нужно так...

вариант со str_replace хреновый и подойдёт только в лучшем случае для <b><i><u> и всё...
Дмитрий Котеров:
Ну Вы просто-таки Колумб в своей области! (-;
Юрий Насретдинов:
("#\(.*?)\#si
Эх.. А что будет если [ b ]something[ /b ] anything [ b ] something else [ /b ] ? Будет все между первым и последним [ b ] жирное. Надо еще квантификатор "U" ставить, чтобы отключить "жадность" BBcode
Евгений Галашин:
("#\(.*?)\#si
? нейтрализует *
Дмитрий Эсс:
yUAC:
Почитай http://www.perldoc.com/perl5.8.0/pod/perlre.html .
Remy:
А как вот этот код:
[link=../guestbook/]
перевести в этот:
<a href='=../guestbook/'>?
Регулярные выражения не знаю просто...
Я не волшебник, я только учусь! :-)
WingedFox:
preg_replace("#\[link=([^]]+)#",'<a href="\\1">,$link);
Remy:
WingedFox:
Огромнейшее merci!!!

Ну, и всем остальным тоже... :-)
WingedFox:
Remy:
Пожалуйста 8*)
Кстати, для ... будет так:
preg_replace("#\[link=([^]]+)\]((?:(?!\[/link]).)+)\[/link]#",'<a href="\\1">\\2</a>',$link);
Remy:
А, ну это я уже давно, с успехом, применяю. :-)
Но все равно спасибо! :-)
Remy:
preg_replace("#\]+)#",'<a href="\\1">,$link);
Вы уверены? Он почему-то "]" забывает...
Дмитрий Эсс:
Remy:
Так добавьте в рег:
preg_replace("#\[link=([^]]+)]#",'<a href="\\1">,$link);
Remy:
Уже давно! :-)
Наугад, правда... Но с плюсом!
$info=preg_replace("#\[link=([^]]+)+]#", "<a href='\\1'>", $info);
WingedFox:
Remy:
Надо не "наугад", а читать книжки.
Фридла, например.
Уберите "+" подальше из рега.
Remy:
Уберите "+" подальше из рега.
Совсем? А что, он так опасен?
Надо не "наугад", а читать книжки.
Может позже?! Сейчас свободного времени, с этими экзаменами, совсем нет...
Причем, не только на такие книжки, а еще и на книжки о PHP!!!
Ужас, правда?
Дмитрий Эсс:
Ужас, правда?
Реальность.
Совсем? А что, он так опасен?
Он там не нужен.
WingedFox:
Remy:
Хорошие книжки читаются на одном дыхании и экзаменам не мешают. =)
Remy:
А времени все равно нет...
Евгений Галашин:
Remy:
Почитайте дзенский форум...
Remy:
Почитайте дзенский форум...
Хорошо.
Remy:
Помогите, пожалуйста!
В гостевой книге, в цикле, использую такую конструкцию:
$text_m=preg_replace("(:$counter:)", "<img src='./$smilesdir/$file' border='0'/> ", $text_m);
должна заменять (:число:) на соответствующее изображение... но заменяет не как надо, а именно: изображение оказывается в скобках (изображение), что не так?
WingedFox:
Remy:
Внимательно читаем описание синтаксиса регов.
Remy:
WingedFox:
Неделю читаю...
Ладно, скачаю свой старый вариант с сервера, исправлю...
WingedFox:
/\(:$counter:\)/
Remy:
Ох, летом учить и учить...
http://forum.dklab.ru/other/all/Javascript_2.html
Remy:
WingedFox:
А вообще, большое, Вам, спасибо! :-)
WingedFox:
Remy:
Большое "на здоровье"! 8*)
Remy:
Опять проблема: :-(
Есть файл, примерно такого содержания:

(link=../guestbook/)(prenom=Guestbook)Гостевая книга(/prenom)
(link=http://bestactors.ru/forum/)(prenom=forum)Форум на сайте bestactors.ru(/prenom)

Пытаюсь его зарегить, но получается такой результат:
При замене (prenom=Guestbook)Гостевая книга(/prenom), заменяется прекрасно, но в результате остается и (link=../guestbook/), а он ну совсем не нужен...
Юрий Насретдинов:
Remy:
Здорово, и что, опять телепаты отдыхают :evil: ? Какой код это делает, на что заменяет, и т.д. !!!
Remy:
Вот код:

$row="(link=../guestbook/)(prenom=Guestbook)Гостевая книга(/prenom) "; //Исходная строка
$link=preg_replace("#\[link=([^]]+)]#", "\\1 ", $row); //присванивание переменной $link значение
$prenom=preg_replace("#\[prenom=([^]]+)\]((?:(?!\[/prenom]).)+)\[/prenom]#","\\1", $row); // --//--//--
$commentaire=preg_replace("#\[prenom=([^]]+)\]((?:(?!\[/prenom]).)+)\[/prenom]#","\\2", $row); // --//--//--

$return.=" <tr><td class='' onClick='location.href=\"$link\"'>$prenom</td><td>$commentaire</td></tr>\n"; //результат

Юрий Насретдинов:
Remy:
А кто слеши перед «]» ставить будет ?
Anonymous:
И это все?
Ant:
И это все?
Это у Вас надо спросить.
Пришедний:
WingedFox, подскажи каким должен быть регексп для .jpg]описание?
После обработки этой регой:
preg_replace("#\[link=([^]]+)\]((?:(?!\[/link]).)+)\[/link]#",'<a href="\\1">\\2</a>',$link);
Выходит:
<a href="http://www.sitename.net/imgname[1">.jpg]описание</a>
WingedFox:
Пришедний
Примерно так:

preg_replace("#\[link=((?:[^]]|](?=\.\w{2,4}))+)\]((?:(?!\[/link]).)+)\[/link]#",'<a href="\\1">\\2</a>',$a);

Но я бы поубывав за такие имена картинок =)
Пришедний: спасибо WingedFox'у
Ай спасибо тебе WingedFox - добрый ты человек! Выручил... Теперь буду захаживать к Вам чаще.
Д.:
А вот здесь выложена реализация BBCoda без регов: http://www.pc.uz/documents/text/732.html На конечных автоматах.
Satyrius:
Еще раз: бороться с малой производительностью следует методом кэширования, и никак иначе. Это единственный способ, который позволяет не портить исходные данные и в то же время добиться такой же скорости работы, которая была бы при их «порче».

Сколько ж раз говорить, что кэширование — это не дублирование данных. Дублированием оно было бы, если бы потеря «дублированных» данных вела к неработоспособности системы, или если бы система не могла работать в отсутствии дубликата. Т.к. и то, и другое неверно, то никакое это не дублирование.

Дмитрий, хотелось бы спросить вашего совета. Как лучше организовать кэширование?

Имеется гостевая книга:

CREATE TABLE (
mesID int not null auto_increment primary key,
mesDate timestamp,
mesAuthor varchar(50),
message text
);


В поле text содержится исходный текст сообщения. А куда писать кэш? Создать в таблице поле, например mesCache, и записывать туда готовое для вывода сообщение (после замены bb-кодов и т.п.), или создать вторую таблицу, связать ее с первой по mesID, и уже в ней хранить кэш. Или есть другой более правильный подход? И не накладно ли будет хранить кэш (я про объем), ведь размер кэшированного сообщения будет почти такой же как и исходного?
Юрий Насретдинов:
Я думаю, если критична производительность, пихайте в другую таблицу, не очень критична - можете в ту же самую. Вам, видимо, лучше в другую.
Satyrius:
Юpий Насрeтдинов
Зашел вопрос о критичности и некритичности производительности. А чем эта самая производительность будет убита, если кэш хранить в той же таблице? Проблемы будут из-за увеличивающегося вдвое размера таблицы или тут какие-то другие причины?
Юрий Насретдинов:
А чем эта самая производительность будет убита, если кэш хранить в той же таблице?
Можете кстати сами проверить - проведите эксперимент, сделайте таблицы с 10000 записей:
1) в таблице текст сообщения + там же кэш
2) в одной таблице текст сообщения, в другой - кэш

Измерьте среднюю скорость выборки порядка 10-15 произвольных сообщений из обоих таблиц, и посмотрите, какова разница :). Скорее всего Вы её не заметите. А можете и заметить. В любом случае, вариант с раздельным хранением кэша и сообщений должен работать быстрее, т.к. размер одной записи будет меньше => меньше размер файла базы данных, меньше нагрузка на базу данных и файловую систему. Это в теории.
Kotofeich:
А подскажите как отпарсить строку http://mysite.ru

Эта тема на forum.dklab.ru