Перейти к контенту
  • 0

Создание очень изощренного BB-кода


Grandious

Вопрос

Здравствуйте!

 

Есть необходимость создать собственный BB-код, обработка которого будет производиться во внешнем php-скрипте. Где я должен внутри php ловить {content} и {option} для дальнейшей обработки? В $_POST[] ? То есть, я имею в виду, происходит ли вызов этого скрипта внутри самой IPB типо как foo.php?content=<content>&option=<option> или все на самом деле намного сложнее? Или проще?

Ссылка на комментарий
Поделиться на других сайтах

Рекомендуемые сообщения

  • 0

Все проще. Вы указываете свой скрипт в описании бб-кода в админке и кладете его в /admin/sources/classes/text/parser/bbcode .
В этом скрипте у вас класс bbcode_plugin_{key} ({key} вы указали в свойствах кода в админке) , расширяющий bbcode_parent_main_class

bbcode_parent_main_class надо убедиться что загружен, для этого перед описанием класса вставьте: 

if( !class_exists('bbcode_parent_main_class') ) { require_once( IPS_ROOT_PATH . 'sources/classes/text/parser/bbcode/defaults.php' ); }

У этого класса следующие методы:

Конструктор:

public function __construct( ipsRegistry $registry, $_parent=null )
{
	$this->currentBbcode	= 'НАЗВАНИЕ КОДА';
 
	parent::__construct( $registry, $_parent );
}

Обязательный метод замены:

protected function _replaceText($txt)
{
	$_tags = $this->_retrieveTags();//получаем наш бб-код из настроек

	foreach( $_tags as $_tag )//у нас в IPB3 у бб-кода может быть псевдоним. Это значит, что передается в любом случае массив с тэгом или тэгами, которые надо заменить.
	{
		$txt = preg_replace( "/\[{$_tag}\](.+?)\[\/{$_tag}\]/i", "<div style='float:left;'>\1</div>", $txt );//тут происходит обработка. $txt-текст всего сообщения. в данном случае ббкод заменяется на html прижимающий содержимое тегов к левому краю. Если у вас ббкод с option, то будет и в регулярке \[{$_tag}=([^\[]+?)\] и тот самый option будет \1 в шаблоне замены, а content станет \2.
	}

	return $txt;
}

Ну и есть еще могут быть  preDbParse, preEditParse и preDisplayParse, но не обязательно. Примеры смотрим в файле со встроенными кодами admin\sources\classes\text\parser\bbcode\defaults.php

 

Под кат пихну статью с сайта инвижина про бб-коды в 3.4, а то они все поудаляли:

 

[3.4+] Custom BBCode PHP Changes

Guide added by Charles Warner, Oct 25 2012 09:19 AM (Updated Dec 13 2012 09:11 AM)


There are some changes to the custom BBCode parser that means you'll need to update your custom BBCode PHP classes.
 
These are as follows:
 
Parent loader and class names
If you have a dynamic loader at the top of your file, it now needs to point to the new defaults.phpif( !class_exists('bbcode_parent_main_class') )
{
    require_once( IPS_ROOT_PATH . 'sources/classes/text/parser/bbcode/defaults.php' );/*noLibHook*/
} 
Your custom bbcodes will now need to extend the class bbcode_parent_main_class instead ofbbcode_parent_class as they did in IP.Board 3.3 and below, and you should no longer implement the bbcodePlugin interface.
 
Additionally, your custom bbcode classnames should now be bbcode_plugin_{key} instead ofbbcode_{key} as they were in IP.Board 3.3 and below.
 

__construct
This now needs a second parameter to capture the parent:
Example:
  1. public function __construct( ipsRegistry $registry, $_parent=null )
  2. {
  3.     $this->currentBbcode    = 'sharedmedia';
  4.  
  5.     parent::__construct( $registry, $_parent );
  6. }
 

Location of custom PHP files
 
Custom BBCode PHP files should now be placed in /admin/sources/classes/text/parser/bbcode (in IP.Board 3.3 and below they were found in /admin/sources/classes/bbcode/custom)
 

 

 

Ссылка на комментарий
Поделиться на других сайтах

  • 0

 

 

В этом скрипте у вас класс bbcode_plugin_{key} ({key} вы указали в свойствах кода в админке

 

Не нашел в админке такого свойства... Может, вы имели в виду просто имя тэга, как оно выглядит без квадратных скобок?

 

Класс bb_code_plugin_{key} я должен первым делом объявить в своем скрипте и прописать его как наследника bb_code_parent_main_class?

Изменено пользователем Grandious
Ссылка на комментарий
Поделиться на других сайтах

  • 0

Не имя, а ключ, он совпадает с тем, что вы пишите в квадратных скобках в сообщении. Для будет bb_code_plugin_img extends bbcode_parent_main_class

Откройте admin\sources\classes\text\parser\bbcode\defaults.php и посмотрите, там таких классов больше десятка объявлено.

 

И вот это не забудьте:
 

bbcode_parent_main_class надо убедиться что загружен, для этого перед описанием класса вставьте: 

так что не первым делом

Ссылка на комментарий
Поделиться на других сайтах

  • 0

Да-да, я понял. Спасибо, буду разбираться!


Я правильно понимаю, что в

 

protected function _replaceText($txt)

 

$txt - это и есть тот самый {content}, который я обрабатываю и изменяю?

Ссылка на комментарий
Поделиться на других сайтах

  • 0

нет.

 

$txt-текст всего сообщения.

контент это в регулярке вида \[{$_tag}=([^\[]+?)\](.+?)\[\/{$_tag}\]/i будет вторая извлекаемая группа. первая скобка - $1 - {option}, вторая - $2 - {content}, а сама регулярка применяется ко всему тексту - $txt . 

Ссылка на комментарий
Поделиться на других сайтах

  • 0

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

Ссылка на комментарий
Поделиться на других сайтах

  • 0

Регулярные выражения - устоявшийся промышленный стандарт, результат полувековой эволюции обработки текстовой информации. Если хотите использовать любой язык для работы с текстом - без регулярных выражений не обойтись. Для начала почитайте соответствующую статью в википедии, потом экспериментируйте на тренажере , он от Ruby on Rails, но регулярки везде одинаковые, если не влезать в тонкости.
 

Ссылка на комментарий
Поделиться на других сайтах

  • 0
Да собственно, насколько я помню, по некоторым вопросам, типа замены в строке, идут споры, что быстрее - регулярки или прямой подход
Ссылка на комментарий
Поделиться на других сайтах

  • 0
Само собой замена фиксированной строки намного быстрее, чем подстановка по шаблону и правилам. Тут нет сомнений и вопросов.
 
Но данная задача не решается фиксированной заменой. Алгоритм в виде циклов скорее всего будет медленнее регулярки.
"найти позицию включения подстроки открывающего тега", внутри 2 операции "найти позицию опций тега(то что после равно и до квадратной скобки)" и "найти позицию ближайшего закрывающего тега". Получаем для каждого включения тега 3 поля - "позиция открытия", "позиция закрытия+длина закрывающего тега" и option. Из них создаем строку для замены. Заменяем текст между  "позиция открытия" и "позиция закрытия+длина закрывающего тега". Прибавляем длину строки для замены к "позиция открытия" и с полученного номера символа снова ищем следующий открывающий тег.
 
Ссылка на комментарий
Поделиться на других сайтах

  • 0

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

Тут еще вопрос ресурсоемкости не последний.

Простой пример: сделал себе на форум тег спойлера. Только у меня иногда под спойлер большие тексты выкладываются. На регулярке больше 180 К букв регулярка вылетала; substr() в цикле отлично обрабатывает и тексты в 100 раз больше.

Ссылка на комментарий
Поделиться на других сайтах

  • 0

контент это в регулярке вида \[{$_tag}=([^\[]+?)\](.+?)\[\/{$_tag}\]/

 

Как ни бился, не смог понять, что делают прямые слеши здесь?

 

 

"/\[{$_tag}\](.+?)\[\/{$_tag}\]/i"

 

а здесь они зачем?

а в этом выражении

 

 

 

"<div style='float:left;'>\1</div>"

 

что такое "\1"?

 

Что значат скобки? Почему "(.+?)" надо обязательно в скобках? 

 

Я не нашел об этом нигде ничего, а вы применяете...

Ссылка на комментарий
Поделиться на других сайтах

  • 0

http://php.net/pcre

 

offtop:

ну а конечный автомат с состояниями тоже никто не отменял

нашли открывающий тег [tagname

перешли в состояние 1, запомнили начало

нашли =, перешли в 2, считали опции до ]

не нашли, или считали до ] - перешли в 3, считали текст до [/tagname], запомнили конец

получили 4 переменные - начало, опцию, текст и конец

сделали новый текст, заменили по началу и концу

Ссылка на комментарий
Поделиться на других сайтах

  • 0

Скобки нужны, чтобы выделить группу символов и запомнить ее. Потом к ней можно будет обратиться через \1 \2 .. \n по номеру группы.

 

 

 

Группировка Обозначение группы

Круглые скобки используются для определения области действия и приоритета операций. Шаблон внутри группы обрабатывается как единое целое и может быть квантифицирован. Например, выражение (тр[ау]м-?)* найдёт последовательность вида трам-трам-трумтрам-трум-трамтрум.

Обратная связь

Одно из применений группировки — повторное использование ранее найденных групп символов (подстрокблоковотмеченных подвыражений). При обработке выражения подстро́ки, найденные по шаблону внутри группы, сохраняются в отдельной области памяти и получают номер начиная с единицы. Каждой подстроке соответствует пара скобок в регулярном выражении. Квантификация группы не влияет на сохранённый результат, то есть сохраняется лишь первое вхождение. Обычно поддерживается до 9 нумерованных подстрок с номерами от 1 до 9, но некоторые интерпретаторы позволяют работать с бо́льшим количеством. Впоследствии в пределах данного регулярного выражения можно использовать обозначения от \1 до \9 для проверки на совпадение с ранее найденной подстрокой.

 

 

Точка - любой символ. Плюс после нее означает повторение от 1 до бесконечности. Вопрос после плюса - это "ленивый" квантификатор, означает, что .+ будет искать самую короткую последовательность, если плюс не ставить, то .+ съест все до последнего закрывающего тега.

 

Жадная и ленивая квантификация


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

В некоторых реализациях квантификаторам в регулярных выражениях соответствует максимально длинная строка из возможных (квантификаторы являются жаднымиангл. greedy). Это может оказаться значительной проблемой. Например, часто ожидают, что выражение(<.>) найдёт в тексте теги HTML. Однако, если в тексте есть более одного HTML-тега, то этому выражению соответствует целиком строка, содержащая множество тегов.

Эту проблему можно решить двумя способами.

  1. Учитывать символы, не соответствующие желаемому образцу (]*>) для вышеописанного случая).
  2. Определить квантификатор как нежадный (ленивыйангл. lazy) — большинство реализаций позволяют это сделать, добавив после него знак вопроса.

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

 

 

Это все написано в википедии точно, еще на паре сотен специальных ресурсов про регулярки и в документации php по функциям preg_* .
 

 

Прямые слеши - символы начала и окончания регулярного выражения в данном случае, после закрывающего слеша идут модификаторы, в данном случае i означает нечуствительность к регистру символов. Прямые слеши можно заменить на # или еще какой-то спец.символ, если так удобнее, чем открыл preg_match тем и закрывай. Прямой слеш внутри выражения заэкранирован обратным и означает сам себя.
 


ну а конечный автомат с состояниями тоже никто не отменял нашли открывающий тег [tagname перешли в состояние 1, запомнили начало нашли =, перешли в 2, считали опции до ] не нашли, или считали до ] - перешли в 3, считали текст до [/tagname], запомнили конец получили 4 переменные - начало, опцию, текст и конец сделали новый текст, заменили по началу и концу

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

 

"найти позицию включения подстроки открывающего тега", внутри 2 операции "найти позицию опций тега(то что после равно и до квадратной скобки)" и "найти позицию ближайшего закрывающего тега". Получаем для каждого включения тега 3 поля - "позиция открытия", "позиция закрытия+длина закрывающего тега" и option. Из них создаем строку для замены. Заменяем текст между  "позиция открытия" и "позиция закрытия+длина закрывающего тега". Прибавляем длину строки для замены к "позиция открытия" и с полученного номера символа снова ищем следующий открывающий тег

while ($pos=strpos($text,'[тег',$start)){//ищем в цикле следующий открывающий тег
	$start = $pos + strlen('[открывающий_тег') + 1 ; //выставляем старт на следующий за тегом символ
	if (substr($text,$start,1)=='='){ //проверяем, что у нас [тег=..., т.е. присутствует option
		$optionend = strpos($text,']',$start+1)-$start; //находим, где кончается option
		$option=substr($text,$start+1,$optionend);//извлекаем option
		$start = $optionend+1;//выставляем стартовую позицию для поиска текста
	}else if(substr($text,$start,1)==']')//если option нету, то его извлекать не надо,движемся дальше
	{
		$option = '';
		$start++;//выставляем стартовую позицию для поиска текста
	}else //если после тега ни = ни ] нету, то это возможно [тегеран] :) или еще какой-то другой тег, который тут непричем
	{
		continue;//вываливаемся на следующий проход цикла 
	}

	$end=strpos($text,'[/тег]',$start); //находим конец текста(закрывающий тег)
	$txt=substr($text,$start,$end-$start); //извлекаем текст
//а вот тут бы неплохо впихнуть рекурсию для вложенных тегов.
	$replacement = '<div class=\'{$option}\'>{$text}</div>';//формируем строку для замены
	$text=substr_replace($text,$replacement,$pos,$end+strlen('[/тег]'));//заменяем
	$start = $pos+strlen($replacement);//выставляем старт для следующего прохода цикла и поиска следующего тега
}

Вот такая замена одной preg_replace(). Куда тут состояние впихнуть?

Ссылка на комментарий
Поделиться на других сайтах

  • 0

автомат и написанное на языке программирования это есть разные вещи

Ну в визио или где-то еще алгоритмы рисовать мне лень, показалось проще показать на конкретной реализации. Для целей показа алгоритма я использовал комментарии. 

Ссылка на комментарий
Поделиться на других сайтах

  • 0

я сам бы автомат не нарисовал по всем правилам)

там функции переходов надо очень конкретно описывать идиотскими символами, это не как просто текстом писать)

Ссылка на комментарий
Поделиться на других сайтах

  • 0

Кажется, с регуляркой стало проясняться. Но вот, родился такой код (пока что просто красить красным введенный между тегами текст) - и не работает. То есть, в сообщении тэги получаются as is, никакой замены не происходит.

 

<?
if( !class_exists('bbcode_parent_main_class') ) {
require_once( IPS_ROOT_PATH . 'sources/classes/text/parser/bbcode/defaults.php' );
}

class bbcode_plugin_red extends bbcode_parent_main_class
{

public function __construct( ipsRegistry $registry, $_parent=null )
{
$this->currentBbcode = 'red';

parent::__construct( $registry, $_parent );
}

protected function _replaceText($txt)
{
$_tags = $this->_retrieveTags();

foreach( $_tags as $_tag )
{
$txt = preg_replace( "/\[{$_tag}\](.+?)\[\/{$_tag}\]/i", "<span style='color:red'>\1</span>", $txt );
}

return $txt;
}
 
}

 

Что я здесь не так сделал?

Изменено пользователем Grandious
Ссылка на комментарий
Поделиться на других сайтах

Присоединиться к обсуждению

Вы можете ответить сейчас, а зарегистрироваться позже. Если у вас уже есть аккаунт, войдите, чтобы ответить от своего имени.

Гость
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Ответить на вопрос...

×   Вы вставили отформатированный текст.   Удалить форматирование

  Допустимо не более 75 смайлов.

×   Ваша ссылка была автоматически заменена на медиа-контент.   Отображать как ссылку

×   Ваши публикации восстановлены.   Очистить редактор

×   Вы не можете вставить изображения напрямую. Загрузите или вставьте изображения по ссылке.

Зарузка...
×
×
  • Создать...

Важная информация

Находясь на нашем сайте, вы соглашаетесь на использование файлов cookie, а также с нашим положением о конфиденциальности Политика конфиденциальности и пользовательским соглашением Условия использования.