Задача: построить регулярной выражение и посредством preg_replace сделать рекурсивные замены замены. Имеется текст, в котором встречается PHP: {вариант1|вариант2|вариант3} причем эти конструкции встречаются рекурсивно, т.е. может встречаться PHP: {вариант1|{вариант1_1|вариант1_2}|вариант3}} уровень вложенности от нуля до бесконечности. Регулярка должна обрабатывать этот текст и вместо {вариант1|вариант2|вариант3} => вариант1 (в идеале рандомный вариант, если такое возможно). Simple input: Code: В лесу родилась ёлочка {в лесу она {росла|жила|цвела}|в степу она росла}! Simple output: Code: 1) В лесу родилась ёлочка в лесу она росла! 2) В лесу родилась ёлочка в лесу она жила! 3) В лесу родилась ёлочка в лесу она цвела! 4) В лесу родилась элочка в степу она росла!
Проблему рекурсии решает полностью ) Подскажите тогда какую регулярку применить (без рекурсии). Code: _{v1|v2}_ => _v1_ или _v2_ Не могу выцепить варианты, пробовал так: PHP: \{(((.*)|)+)(.*)\} Возле {} экранирование форум вырезал.
AnGeI /showpost.php?p=2511238&postcount=17490 Для вложенных скобок присваивайте во временную переменную и снова подставляйте. Условие останова - 5 параметр функции http://php.net/preg_replace_callback
Как раз то, что нужно. PHP: $text = 'В лесу родилась ёлочка {в лесу она {росла|жила|цвела}|в степу она росла}!'; function cb($arr) { $arr = explode('|', $arr[1]); return $arr[array_rand($arr)]; } $while = min(substr_count($text, '{'), substr_count($text, '}')); for($i=0; $i < $while; $i++) $text = preg_replace_callback('~\{([^{}]+)\}~','cb',$text); echo $text; Но перебор вариантов (разбор условия) начинается с нижнего уровня, поэтому максимальное число раз обращение к рандомайзеру. Я так понял, чтобы избежать этого нужно текст делить на части, в каждой части имеется только одно глобальное условие и отдельно для каждой части так же обрабатывать и включить жадность в регулярке.
AnGeI Да, количество проходов по тексту равно максимальной вложенности фигурных скобок. Сделать рекурсивное регулярное выражение, которое справится со вложенными элементами - сложно и тормознуто. Я такое когда-то писал, могу поискать
PHP: /* Парсинг сверху вниз с использованием рекурсивного шаблона для выделения блоков верхнего уровня! */ function parseBlock($str){ static $pattern; $pattern = '% (?<=^|[\|]) # начало блока данных (?: [^\{\}\|]* # возможный текст до скобок ( (?P<opn_brt>\{)? # блок в скобках верхнего уровня # содержимое блока (в скобоках) верхнего уровня ( (?P<opn_brt2>\{)? (?:[^\{\}]* | (?-3) ) (?(opn_brt2)\}) [^\{\}]*? )*? (?P<clo_brt> (?(opn_brt) \} ) ) # конец: закр. скобка блока верхнего уровня )? [^\{\}\|]* # возможный текст после скобок верхнего уровня ) %x'; $rez = ''; preg_match_all($pattern, $str, $arr, PREG_SET_ORDER); if(count($arr)==1){ // тескт без альтернатив if( !empty($arr[0][opn_brt]) ){ // если есть составной блок? preg_match('|^(.*?) \{ (.*) \} ([^\{\}]*) $|x', $str, $arr); // содержимое внутри внешних фигурных скобок в $arr[2] $rez = ($arr[1]). parseBlock($arr[2]). ($arr[3]); // рез-т = текст перед скобками + рекурсия + текст после скобок }else{ $rez = $arr[0][0]; // составного блока и альтернатив нет - взять всю строку } }else{ // если есть альтернативы: count($arr)>1 $k = rand(0, count($arr)-1); // взять k - случайный индекс альтернативы $rez = parseBlock($arr[$k][0]); // распарсить ее } return $rez; } $text = 'В лесу родилась ёлочка {в лесу она {росла|жила|цвела}|в степу она росла}!'; echo "Результат: ". parseBlock($text);