Замена псевдотэгов списков [list][*]...[/list]

Qwerty

Новичок
Замена псевдотэгов списков
  • ...

Собственно, нужно одно или несколько рег. выражений, которые заменят псевдотеги списков [ list] на html. Интересует поддержка вложенных списков (допускаю вызов замены циклом). Например:
Код:
[ list=1] 
  [ *]раз 
  [ *]два 
  [ *]три 
  [ list] 
    [ *]три-один 
  [ /list] 
[ /list]
заменить на:
Код:
<ol> 
  <li>раз</li> 
  <li>два</li> 
  <li>три 
  <ul> 
    <li>три-один</li> 
  </ul> 
  </li> 
</ol>
В принципе, интересен и вариант, когда нет необходимости ставить [ *], просто каждая срока между тэгами [ list] и [ /list] считается новым пунктом.
 

sage

Новичок
С помощью строковых ф-ий заменяй [ list=1] на <ol>, [ list] на <ul>, а уже с помощью регулярных выражений - [ *]раз на <li>раз</li>
 

Qwerty

Новичок
Автор оригинала: sage
С помощью строковых ф-ий заменяй [ list=1] на <ol>, [ list] на <ul>, а уже с помощью регулярных выражений - [ *]раз на <li>раз</li>
Ответ неверный... :(
1. Я могу заменить [ list] и [ list=1] на <ul> и </ol>, а кто мне корректно закроет [ /list] тогда? Нет, здесь только парами заменять. Ну, с этим-то я справился (аналогично [ b]...[ /b], например).
2. Как заменить [ *]раз на <li>раз</li> - вот это как раз и есть основной вопрос. Учитывая, что внутри пункта списка может быть \r\n, т.е. символ новой строки нельзя считать окончанием элемента <li>.
 

sage

Новичок
Qwerty
1. да, как-то об этом сразу и не подумал ;)
2.
PHP:
$text = '
  [ *]раз 
  [ *]два 
  и всё ещё два
  [ *]три 
    [ *]три-один';

echo preg_replace('~\[ \*\]([^[]+)~', '<li>\1</li>', $text);
 

Qwerty

Новичок
А если так будет?
Код:
[ list=1] 
  [ *]раз 
  [ *][ b]два[ /b] три
[ /list]
Тут всё не так просто...
 

sage

Новичок
попробуй такое:
PHP:
echo preg_replace('~\[ \*\](.+?)(?=(?:\[ \*\]|\[ /list\]))~s', '<li>\1</li>', $text);
 

Qwerty

Новичок
Пробовал... Проблема со вложенными списками тогда.
Вот код чуть подправленный:
Код:
[ list=1] 
  [ *]раз 
  [ *]два
  [ list] 
    [ *]три 
          в две строки
  [ /list] 
[ /list]
Закрытие </li> произойдет после [ *]два[ list], так?

Добавил еще пункт из двух строк, вдруг захотите по \r\n закрыть </li>. :)
 

sage

Новичок
PHP:
echo preg_replace('~\[ \*\](.+?)(?=\[ \*\]|\[ /?list\])~s', '<li>\1</li>', $text);
 

Qwerty

Новичок
Неее... </li> для пункта [ *]два должно закрываться после закрытия внутреннего [ /list], а не перед его открытием...

Попробую описать замену [ *] русским языком:
Код:
Заменить минимальные фрагменты, начинающиеся [ *]
и заканчивающиеся [ *] или [ /list] (не включая выражение, которым заканчивается),
не содержащие внутри себя непарные псевдотеги [ list]...[ /list]
Нормально? Если нормально, то как реализовать это на регулярных выражениях?
 

sage

Новичок
По-моему, это невозможно сделать с помощью регулярных выражений, возможно, я ошибаюсь ;) Проблема в следующем. Возьмём, например, [ *]два: начинается c [ *] - ставим <li>, проходим дальше: [ *]три - начинается с [ *], но ведь [ *] является также и концом два - ставим </li>. Пишите парсер, одним регулярным, чтоб всё заменил правильно, сделать невозможно.
 

Qwerty

Новичок
Ну почему? Для невложенных списков всё работает идеально. Мы же ищем следующий [ *] с условием невключения в результат поиска (?=...), поэтому он не потеряется.
А в предложенном фрагменте [ *]три не является завершением [ *]два, а находится внутри его.
Мое русское описание замены не впечатлило? :)
Я так думаю, может правда русским языком сначала описать замену?
 
Сверху