Xpoint
   [напомнить пароль]

Регулярные выражения. Вложенные конструкции

Метки: [без меток]
2009-05-01 20:18:47 [обр] Lektor[досье]

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

<?php ## Сравнение "жадных" и "ленивых" квантификаторов.
$str = '[b]жирный текст [b]а тут - еще жирнее[/b] вернулись[/b]';
$to  = '<b>$1</b>';
$re1 = '|\[b\] (.*)  \[/b\]|ixs';
$re2 = '|\[b\] (.*?) \[/b\]|ixs';
$result = preg_replace($re1, $to, $str);
echo "Жадная версия: ".htmlspecialchars($result)."<br>";
$result = preg_replace($re2, $to, $str);
echo "Ленивая версия: ".htmlspecialchars($result)."<br>";
?>

и результат

жадная версия: <b>Жирный текст [b]а тут еще жирней [/b] вернулись </b>
ленивая версия: <b>Жирный текст [b]а тут еще жирней </b> вернулись [/b]

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

<span style="color: red;">цветной текст <span style="font-size: 16px;">большой текст</span>цветной текст</span>

сделать:

[color=red]цветной текст [size=16]большой текст[/size]цветной текст[/color]

Помогите с алгоритмом .. я тут читал одну тему(закрытую) Регулярные выражения. Вложенные конструкции
и там такой вариант увидел:

до_тех_пор_пока ( совпадает выражение в строке ) {
  найти_и_заменить (выражение в строке на обработанную строку) // удалить совпадение
}

я решил заменять совпадения начиная с самого внутреннего т.е. в данном случае: <span style="font-size: 16px;">большой текст</span>
пишу такой патерн:

$text="<span style=\"color: red;\">цветной текст <span style=\"font-size: 26px;\">большой текст</span> цветной текст</span>";
echo $text = preg_replace("#<span style=\"(.*?): (.*?);\">(.*?)(?!<span).*?</span>#si", "[\\1=\\2]\\3[/\\1]", $text);

получаю

[color=red][/color] цветной текст</span>

я так понимаю я не правильно использую негативный поиск вперед. Я рассуждаю так: найти <span blabla>дальше захватить все символы до закрывающего тега </span> но только если на пути не встречается открывающий тег спан.
Надеюсь на помощь.

спустя 2 часа 46 минут [обр] Lektor[досье]

Та тема очень помогла ... сделал по аналогии:

$text="<span style=\"color: red;\">this is first<span style=\"font-size: 26px;\"> this is second </span>first</span>";
while (preg_match("#<span style=\"((?:[^>]*?)):\s((?:[^>]*?));\">(((?!<span ).)*?)</span>#sie", $text, $match))
{
   $search = "#".preg_quote($match[0])."#si";
   $replace = "[".$match[1]."=".$match[2]."]".$match[3]."[/".$match[1]."]";
   $text = preg_replace($search, $replace, $text);

}
   $text = preg_replace("#\[font-size=(\d+)px\](.*?)\[/font-size\]#si", "[size=\\1]\\2[/size]", $text);

echo $text;

Powered by POEM™ Engine Copyright © 2002-2005