Перейти к контенту
  • 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
Ссылка на комментарий
Поделиться на других сайтах

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

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

Гость
Ответить на вопрос...

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

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

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

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

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

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

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

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