ну так я получил этот толчек за что в принципе благодарен. потом допилил собственный вариант отталкивая от вашего, вот он: Код (PHP): function grt($str) { $fns = function($data) { $temp = explode('|', $data[1]); return $temp[ rand( 0, sizeof($temp)-1 ) ]; }; while ( strpos($str, '{') !== false ) { $str = preg_replace_callback('/\{([^\{]+?)\}/', $fns, $str); } return $str; } Насчет производительности я не задумывался ( особенно после того как мне отбили желание думать о ней - viewtopic.php?f=13&t=49108&p=390548 ), для меня было важно написать, коротки логический и понятный код, вроде как мне это удалось.
Есть определённая граница где по затратам времени от регулярок становится больше пользы чем вреда и наоборот. Думаю ни для кого не секрет, что php выполняет байт-код который формируется на лету. И если исходная строка совсем простая, то выгоднее вызвать пару обычных нативных функций чем одну регулярку. Да, в обоих случаях будет похожий байт-код с вызовом с-шной нативщины, но согласитесь, запускать грамоздкий нативный движок регулярок не совсем выгодно для простых строк. Вот и получается, что в простых случаях регулярки только жрут время процессора. Но если текст сложный, например если нужна поддержка {}| в тексте, то проще пройтись по тексту механизмом регулярок чем разобрать его скриптовыми алгоритмами с применением while, foreach, кучей вызовов других нативных функций и тд, т.к. всё это сгенирирует километровый байт-код на выполнение которого уйдёт куча процессорного времени(ведь на разбор и выполнение байт-кода тоже уйдёт время), вот и получается грань когда от регулярок больше пользы в плане затрат времени. Добавлено спустя 13 минут 48 секунд: В той теме вы просто попытались сделать за php работу которую он и сам знает как делать. В документации по php написано что не стоит использовать ссылки только ради оптимизации, тк php сам занимается оптимизацией таких моментов. Например один из методов внутренней оптимизации передачи аргументов является представление аргументов как жёстких ссылок в файловой системе. То есть если аргумент был изменён внутри функции куда его передали, то происходит копирование значения, если нет, то аргумент как бы сам собой передаётся по ссылке. Но в остальном оптимизация очень важна
мои варианты без регулярок Код (PHP): $p1=$p2=false; while (($p2 = strpos($str,'}'))!==false && ($p1 = strrpos(substr($str,0,$p2),'{'))!==false) { $a = explode('|', substr($str, $p1+1,$p2-$p1-1)); $str = substr_replace($str, $a[rand(0,count($a)-1)], $p1, $p2+1-$p1); } с регулярками Код (PHP): while (preg_match("/\{([^{}]+?)\}/", $str)) { $str= preg_replace_callback("/\{([^{}]+?)\}/",create_function('$s','$a=explode("|",$s[1]);return $a[rand(0,count($a)-1)];'),$str); } время мы не мерили. интересен был сам подход.
Ну второй вариант тут предлагал ТС. Первый интересно будет замерить. Довольно своеобразный вариант(в хорошем смысле) Но что-то подсказывает что на средних и больших текстах будет медленней т.к. строка обрабатывается несколько раз(в зависимости от количества {} и каждый раз строка обрабатывается заново). И ни один вариант {}| в тексте не поддерживает. Ни в коем случае не в упрек, просто анализирую Итак, код для тестирования Код (PHP): //$source = '{Привет|Здравствуйте|Добрый день} Александр!'; //$source = '{ей,|хей,}{привет|добрый день}'; //$source = 'Привет {{Виктор|{Антон|Антонио|Антошка}|Сергей}|{Господин|Сэр|Товарищ}} как {твои|ваши} дела'; //$source = 'В языке {{C++|C}|{JavaScript|PHP}|C#|Java} блоки кода можно объединять в фигурные скобки, например \{{ВАШ КОД|КАКОЙ-ТО КОД};\}<br>Условия записываются так {if(1)|if(1\|\|0)}{\{do_something();\}|\{do_some_work();\}}'; //$source = '{{в1|в2}|{в3|{в10|в11|в12}|{в101|{в222|в333|в444}|в123}|{в13|в14|в175}}|{в6|в7}} александр {{в1|в2}|{в3|{в10|в11|в12}|{в101|{в222|в333|в444}|в123}|{в13|в14|в156}}|{в6|в7}} дмитрий'; $start = microtime(true); $str = $source; $str = preg_replace_callback('#(\{[\s\S]+?\})([^\|\{\}]+)#', function($mathces) { $mathces[1] = str_replace(array('}','{'), '', $mathces[1]); $arr = explode('|', $mathces[1]); return $arr[array_rand($arr)].$mathces[2]; }, $str); echo $str.'<br>'; echo number_format(microtime(true)-$start, 6).'<br><br>'; //============================================= $start = microtime(true); $str = $source; $str = preg_replace_callback('#(?<!\\\)(\{[\s\S]+?(?<!\\\)\})(?![\|\}])#', function($mathces) { $mathces[1] = preg_replace('#(?<!\\\)\{|(?<!\\\)\}#', '', $mathces[1]); $arr = preg_split('#(?<!\\\)\|#', $mathces[1], -1,PREG_SPLIT_NO_EMPTY); return preg_replace('#(?<!\\\)\\\#', '',$arr[array_rand($arr)]); }, $str); echo str_replace(array('\{', '\}'), array('{', '}'), $str).'<br>'; echo number_format(microtime(true)-$start, 6).'<br><br>'; //============================================= $str = $source; $start = microtime(true); $p1=$p2=false; while (($p2 = strpos($str,'}'))!==false && ($p1 = strrpos(substr($str,0,$p2),'{'))!==false) { $a = explode('|', substr($str, $p1+1,$p2-$p1-1)); $str = substr_replace($str, $a[rand(0,count($a)-1)], $p1, $p2+1-$p1); } echo $str.'<br>'; echo number_format(microtime(true)-$start, 6); Результаты Добавлено спустя 13 минут 21 секунду: для строки ================================ для строки ================================ для строки ================================ для строки ================================ для строки Добавлено спустя 53 минуты 5 секунд: в вашем варианте ошибка. подправил Код (PHP): while (($p2 = strpos($str,'}'))!==false && ($p1 = strrpos(substr($str,0,$p2),'{'))!==false) { $sub = substr($str, $p1+1,$p2-$p1-1); $a = explode('|', $sub); $str = str_replace('{'.$sub.'}', $a[array_rand($a)], $str); } вот результаты с подправленным вариантов порядок тот же: - мой без поддержки {}| в тексте - мой с поддержкой {}| в тексте - ваш Для строки: ======================== Для строки: ============================== Для строки: =========================== Для строки: ================================ Для строки: обратите внимание, как я и говорил - чем больше {} тем больше времени занимает ваш вариант, т.к. рекурсия
в вашем тоже(первом). с вложенными вариантами глючит например Код (PHP): $str = '{Пожалуйста|Просто} сделайте так, чтобы это предложение {изменялось {Быстро|Мгновенно} случайным образом}'; иногда ваш код выдает: -Просто сделайте так, чтобы это предложение Мгновенно случайным образом} -Пожалуйста сделайте так, чтобы это предложение изменялось Быстро случайным образом} съедает слово 'изменялось'
ну я то свой код писал не под это конкретное условие. там условие было другое. потому неудивительно что мой код неработает для ВАШИХ входных данных. теперь ваш выдает Пожалуйста сделайте так, чтобы это предложение {изменялось|{Быстро|Мгновенно}|случайным образом} ))
Посмотрите предыдущие сообщения, для варианта без поддержки {}| если строка заканчивается знаком } то нужно добавить пробел в конце. По условиям нашей задачи всё что внутри {} будет вариантом внезависимости от уровня вложений Добавлено спустя 53 секунды: Так я же подправил его чтобы работал
ненужно подменять понятия я привел такую сроку на вход: Код (PHP): $str = '{Пожалуйста|Просто} сделайте так, чтобы это предложение {изменялось {Быстро|Мгновенно} случайным образом}'; Код (PHP): $str = '{Пожалуйста|Просто} сделайте так, чтобы это предложение {изменялось|Быстро|Мгновенно}|случайным образом}'; не нужно вставлять | там где вам выгодно. Вторая группа скобок не обязана иметь более одного варианта. это частный случай, и он имеет право на существование. но если вам так будет легче. исправлю Код (PHP): $str = '{Пожалуйста|Просто} сделайте так, чтобы это {изменялось {Быстро|Мгновенно} случайным образом|не менялось}'; с этим ваш код также глючит. а следовательно нет смысла мериться письками. сначало нужно чтоб алгоритм хотябы работал)
Ну давайте вы внимательно посмотрите и убедитесь что вы не везде поставили | И прочитайте пожалуйста условие задачи от ТС. вы же заявили что решили эту задачу вот мы и стали проверять ваш алгоритм. И никто тут письками не мериится. Если вам не хочется развиваться и узнавать что-то новое, то и не нужно в штыки всё принимать Если уровень вложенности влияет на вариант, то да, нужна рекурсия либо написать токенизатор чтобы не сканировать каждый раз всю строку. Добавлено спустя 1 минуту 2 секунды: Задачу ТС считаю полностью решённой ещё полторы страницы назад...
я просто проверяю ваш код ТС написал: беру ваш вариант кода и приведенные ТС-ом входные данные: Код (PHP): $str = '{{вариант_1_1|вариант_1_2}|{вариант_2_1|вариант_2_2|вариант_2_3}}'; ваш код выдает ЧЯДНТ ?
Ну я же вам только что написал Добавлено спустя 3 минуты 57 секунд: Либо используйте код с поддержкой {}| Добавлено спустя 3 минуты 30 секунд: По крайней мере ТС не жаловался. Если бы надо было другой формат, он бы меня поправил я думаю
это называется костыль. заявленный вами код не работает на входных данных ТСа. пробел тут пробел там... тоесть на шаблоне с пробелами в разных местах ваш код неработает. например на таком Код (PHP): $str = '{{вариант_1_1|вариант_1_2} |{вариант_2_1|вариант_2_2}} '; извините, но код либо работает либо нет. ваш - нет. он не должен зависеть от пробела или его отсуствия. пока незаработает на всем спектре входных данных - даже обсуждать нечего.
Я что, коммерческий код тут пишу? Я итак за ТС сделал всю работу и мне тут какие-то упреки ещё... Если вообще всё делать за человека думать он не научится. Я думаю он в состоянии вставить в первый вариант один несчастный if на проверку последнего символа. Либо использовать второй вариант.
да какие упреки. просто указал на то что есть проблемы в реализации кода. и нужно СНАЧАЛА решить эти проблемы. а уже ПОТОМ мерить его скорость и заниматься оптимизацией. если ТСа код устраивает - хорошо. но пусть знает где и какие проблемы могут его ждать на разных входных данных
Если вы всё-таки прочтете тему, то увидите что все эти моменту я для ТС расписал максимально подробно Добавлено спустя 1 минуту 37 секунд: Смысл любой помощи в том, чтобы человек что-то вынес из нее и проанализировал и возможно доработал а не тупо скопировал код Добавлено спустя 39 секунд: Иначе думать самостоятельно он не научится никогда Добавлено спустя 2 минуты 22 секунды: Вы действительно считаете что вставка пробела в конец строки и спецсимвола между неразрывными {}{} убьет производительность? Тем более что второй вариант лишен этих ограничений
Всем участникам беседы! Интересуют варианты в которых будут присутствовать вложения во вложениях, т.е. вот так вот: Код (PHP): $str = 'Привет {{Виктор|{Антон|Антонио|Антошка}|Сергей}|{Господин|Сэр|Товарищ}} как {твои|ваши|} дела'; или Код (PHP): $str = '{Пожалуйста|Просто} сделайте так, чтобы это предложение {изменялось|{Быстро|Мгновенно}|случайным образом}';
Просто добавьте рекурсию во второй вариант Добавлено спустя 3 минуты 57 секунд: Это если нужно учитывать уровень вложения
расписал всё в статье и указал вариант с рекурсией который кушает все варианты http://smelukov.com/%D1%80%D0%B0%D0%B7%D0%B1%D0%B8%D1%80%D0 ... p-opcodes/
ваш итоговый вариант - фактически повторяет приведенный ранее мной. только строковые функции заменили на регулярки. из минусов, как вы сами говорили: тоесть вариант для поиска каждого блока сканирует строку ЗАНОВО сначала, КАЖДЫЙ РАЗ. могу предложить еще один альтернативный алгоритм (типа стековый автомат). плюс его в том, что он парсит все вложенные блоки ЗА ОДИН ПРОХОД: Код (PHP): $prev = null; $tmp = array(); $i = $j =0; $out = ''; $str = '{Пожалуйста|Просто} пусть \{это\} предложение {меняется {БЫСТРО|МГНОВЕННО|за {1|2|3} секунды} случайным образом|не меняется}.'; preg_match_all("/./us", $str, $m); foreach($m[0] as $c) { if ($c=='{' && $prev!='\\') { // begin block ++$i; } else if ($c=='|' && $prev!='\\') { // OR ++$j; } else if ($c=='}' && $prev!='\\') { // end block if ($i>1) { // multi lvl $prev_keys = array_keys($tmp[$i-1]); $j = array_pop($prev_keys); // склеиваем с предыдущим значением стека $tmp[$i-1][$j] .= $tmp[$i][array_rand($tmp[$i])]; } else { // first lvl $out .= $tmp[$i][array_rand($tmp[$i])]; $j=0; } $tmp[$i] = null; --$i; } else { // chars if ($i>0) { if (!isset($tmp[$i][$j])) { $tmp[$i][$j] = null; } $tmp[$i][$j] .= $c; } else { $out .= $c; } } $prev = $c; }//foreach echo $out; P.S. по скорости возможно это будет не быстрее вашего. ибо в php посимвольная работа с юникод строками не самое сильное место.
Да, посимвольно будет медленно, но не только из-за юникода, но ещё и из-за количества итоговых опкодов Добавлено спустя 7 минут 43 секунды: на строке Код (PHP): $str = '{{Сегодня {утром|после обеда}}|Вчера} я {побежал|пошел|поехал{ на автобусе| на машине| на {трамвае|троллейбусе}|}} в {зоо-|компьютерный|интимный|продуктовый} магазин чтобы {купить|украсть} {костюм {совы|{человека паука|бэтмена}|Винни-Пуха|колобка}|презерватив}'; мой - 0.0002 ваш - 0.0004
не совсем... за один проход будут заменены все блоки самого нижнего уровня сколько бы их ни было соответственно количество проходов = количеству уровней вложенности а не количеству блоков