С вот этим текстом: Код (Text): $str = 'Привет {{Виктор|{Антон|Антонио|Антошка}|Сергей}|{Господин|Сэр|Товарищ}} как {твои|ваши} дела'; не верно работает код из этого поста - viewtopic.php?f=13&t=48868#p392547 пишет: т.е. сжирает часть текста, который он не должен сжирать. из этого поста - viewtopic.php?f=13&t=48868#p392496 верхний тоже сжирает часть текста, а вот второй работает так как надо. Добавлено спустя 1 минуту 18 секунд: Можете помочь составить регулярное выражение, что бы оно искало текст между { и } но при этом в этом тексте (между { и }) не должно быть {, и я покажу что я имел ввиду.
Ну так я Вам так и сказал, что первый вариант для простой конструкции где сначала идёт {} а потом текст уже без {} А второй вариант как раз под Ваш случай. Ок, буду дома - напишу Добавлено спустя 5 минут 40 секунд: Хотя могу и так прикинуть #\{([^\}]+?)\}# Добавлено спустя 1 минуту 37 секунд: Но тогда ее придётся рекурсивной заменой применить Добавлено спустя 56 секунд: В callback после каждого найденного вхождения модифицировать строку(заменять {вхождение} на рандомный вариант внутри вхождения) и потом снова рекурсивно регуляркой через callback, но уже с новой строкой... Пока всё не заменится Добавлено спустя 21 минуту 38 секунд: Но это уже искусственное усложнение Добавлено спустя 13 минут 37 секунд: Ничего удивительного, т.к. это сокращенный вариант первого варианта, а как я уже говорил ранее:
Код (PHP): function xxx($str) { $fns = function($data) { $temp = explode('|', $data[1]); return $temp[ rand(0, sizeof($temp)-1 ) ]; }; while ( strpos($str, '{') !== false ) { $str = preg_replace_callback('/\{([^\{]+?)\}/sui', $fns, $str); } return $str; } echo( '<div>'. xxx('Привет {{Виктор|{Антон|Антонио|Антошка}|Сергей}|{Господин|Сэр|Товарищ}} как {твои|ваши} дела') .'</div>' ); Я не так глуп как выгляжу
сравнение моего и Вашего варианта на более объемном примере: Код (PHP): function xxx($str) { $fns = function($data) { $temp = explode('|', $data[1]); return $temp[ rand(0, sizeof($temp)-1 ) ]; }; while (true) { if ( strpos($str, '{') === false ) { break; } $str = preg_replace_callback('/\{([^\{]+?)\}/sui', $fns, $str); } return $str; } $start = microtime(true); $str = "{{в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}} дмитрий"; foreach(preg_split('#[^\|\{\}]*(\{[\s\S]+?\}[^\|\{\}]+)#', $str, -1, PREG_SPLIT_DELIM_CAPTURE|PREG_SPLIT_NO_EMPTY) as $entry) { $end_pos = strrpos($entry, '}'); $before = substr($entry, 0, $end_pos); $end = substr($entry, $end_pos+(substr($entry, $end_pos, 1)=='}'?1:0)); $before = str_replace(array('}','{'), '', $before); $arr = explode('|', $before); $str = str_replace($entry, $arr[array_rand($arr)].$end, $str); } echo $str.'<br>'; echo number_format(microtime(true)-$start, 6).'<br><br>'; //============================================= $start = microtime(true); echo( '<div>'. xxx('{{в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}} дмитрий') .'</div>' ); echo number_format(microtime(true)-$start, 6); выдает: Добавлено спустя 1 минуту 32 секунды: а теперь засуньте туда пару статей Добавлено спустя 1 минуту 42 секунды: говорю же - не нужна тут такая рекурсия Добавлено спустя 6 минут 42 секунды: и модицикаторы sui в регулярке не нужны s(определяет символ . как набор любых символов(включая перевод строки)) - не нужно потому что символ . не используется в данной регулярке u(обработка как utf8) - не нужно в том случае если у Вас включена перегрузка функций mb_string i(игнорировать регистр символов) - не нужно тк у Вас в регулярке нет букв Добавлено спустя 5 минут 33 секунды: вместо Код (Text): rand(0, sizeof($temp)-1 ) можно просто написать Код (Text): array_rand($temp)
странная вещь, если брать мелкое предложение и запускать функцию много раз, тогда да, моё творение работает раза в 2 медленнее, а вот если на оборот, взять текст по больше и запускать функцию всего пару раз, то на оборот моё работает быстрее, может я где то накосорезил? Код (PHP): function xxx($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; } function xxx2 ($str) { foreach(preg_split('#[^\|\{\}]*(\{[\s\S]+?\}[^\|\{\}]+)#', $str, -1, PREG_SPLIT_DELIM_CAPTURE|PREG_SPLIT_NO_EMPTY) as $entry) { $end_pos = strrpos($entry, '}'); $before = substr($entry, 0, $end_pos); $end = substr($entry, $end_pos+(substr($entry, $end_pos, 1)=='}'?1:0)); $before = str_replace(array('}','{'), '', $before); $arr = explode('|', $before); $str = str_replace($entry, $arr[array_rand($arr)].$end, $str); } return $str; } function test_time($fns) { $str = 'Привет {{Виктор|{Антон|Антонио|Антошка}|Сергей}|{Господин|Сэр|Товарищ}} как {твои|ваши} дела'; $new_str = ''; for ( $i = 0; $i < 1000; $i++ ) { $new_str .= " {$str}"; } $start = microtime(); for ( $i = 0; $i < 5; $i++ ) { $fns($new_str); } $end = microtime(); $result = $end - $start; echo( "<h3>Потрачено времени: {$result}</h3>" ); } echo( "<h2>xxx:</h2>" ); test_time('xxx'); echo( "<h2>xxx2:</h2>" ); test_time('xxx2'); PS текст 'Привет {{Виктор|{Антон|Антонио|Антошка}|Сергей}|{Господин|Сэр|Товарищ}} как {твои|ваши} дела' складывается 1000 раз и он отправляется в функцию.
потому что текст после повторени получается однородный, а движок регулярок неплохо работает с однородным текстом(в реальности-то вряд ли текст будет однородный), но даже в этом случае есть вариант БЕЗ рекурсий.... вот вариант сравнения через preg_replace_callback БЕЗ рекурсий(моем варианте) обратите внимание как реализовано повторение строки(цикл здесь не нужен) Код (PHP): function xxx($str) { $fns = function($data) { $temp = explode('|', $data[1]); return $temp[ rand(0, sizeof($temp)-1 ) ]; }; while (true) { if ( strpos($str, '{') === false ) { break; } $str = preg_replace_callback('/\{([^\{]+?)\}/sui', $fns, $str); } return $str; } //$source = 'Привет {{Виктор|{Антон|Антонио|Антошка}|Сергей}|{Господин|Сэр|Товарищ}} как {твои|ваши} дела'; $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}} дмитрий'; $source = str_repeat($source, 1000); $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); echo( '<div>'. xxx($source) .'</div>' ); echo number_format(microtime(true)-$start, 6); для строки x1000 и для строки x1000 Добавлено спустя 3 минуты 26 секунд: тот же тест для строк без повторений в 1000 раз для для
Посмотрите, я еще усовершенствовал свой вариант.... Теперь, если внутри текста и вариантов надо вывести символ { или } или |, то его всего лишь надо заэкранировать... посмотрите пример... думаю многим будет интересно.... Код (PHP): function xxx($str) { $fns = function($data) { $temp = explode('|', $data[1]); return $temp[ rand(0, sizeof($temp)-1 ) ]; }; while (true) { if ( strpos($str, '{') === false ) { break; } $str = preg_replace_callback('/\{([^\{]+?)\}/sui', $fns, $str); } return $str; } $source = 'В языке {{C++|C}|{JavaScript|PHP}|C#|Java} блоки кода можно объединять в фигурные скобки, например \{{ВАШ КОД|КАКОЙ-ТО КОД};\}<br>Условия записываются так {if(1)|if(1\|\|0)}{\{do_something();\}|\{do_some_work();\}}'; $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>'; //============================================= $start = microtime(true); echo( '<div>'. xxx($source) .'</div>' ); echo number_format(microtime(true)-$start, 6); выдаст Ваш вариант вообще покрамсал {, } и |... да, разница во времени сократилась, но согласитесь, приятнее всетаки иметь возможность использовать внутри вариантов символы {, } и | (которые Ваш вариант просто съедает) теперь тот же текст, только умноженный на 50,000 раз вариант с поддержкой {, } и | в тексте вариант без поддржки {, } и | в тексте Добавлено спустя 9 минут 57 секунд: хотя в случае с короткими фразами, мой вариант с поддержкой {, } и | в тексте занимает больше времени: обусловлено это дополнительной нагрузкой на регулярку так называемыми утверждениями, ну и добавлением preg_split'ов, как Вы можете видеть. но в варинте без поддержки {, } и | в тексте, мой вариант всетаки быстрее и на коротких фразах Добавлено спустя 12 минут 38 секунд: если Вам понадобится использовать пустые варианты например то просто не используйте PREG_SPLIT_NO_EMPTY при вызове функции preg_split на всякий случай вырежу сам код и опишу плюсы и минусы вариант без поддержки {, } и | в тексте Код (PHP): $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); $str.'<br>'; плюсы: - высокая скорость на любых объемах - поддержка любых форматов текста(с очень небольшой оговоркой) минусы: - не поддерживает знаки {, } и | внутри текста - оговорка 1: между рядом стоящими {...}{...} нужно вставлять хотя бы пробел. оговорка 2: в конце текста надо вставлять пробел вариант с поддержкой {, } и | в тексте Код (PHP): $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>'; плюсы: - высокая скорость на больших объемах - поддерживает знаки {, } и | внутри текста - поддерживает любой формат текста(даже рядом стоящие {...}{...}) минусы: - маленькая скорость на мелких выражениях в нашей сфере всегда приходится выбирать между чем-то... фуф... ну вот как-то так....
Товарищ s.melukov позвольте но мне кажется вы сами себе противоречите. Начнем по порядку: 1. Код (PHP): function xxx($str) { $fns = function($data) { $temp = explode('|', $data[1]); return $temp[ rand(0, sizeof($temp)-1 ) ]; }; while (true) { if ( strpos($str, '{') === false ) { break; } $str = preg_replace_callback('/\{([^\{]+?)\}/sui', $fns, $str); } return $str; } //$source = 'Привет {{Виктор|{Антон|Антонио|Антошка}|Сергей}|{Господин|Сэр|Товарищ}} как {твои|ваши} дела'; $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}} дмитрий'; $source = str_repeat($source, 1000); $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); echo( '<div>'. xxx($source) .'</div>' ); echo number_format(microtime(true)-$start, 6); Чем он принципиально отличается от моего варианта? Точно так же вы регуляркой с колбеком обрабатываете, я регуляркой очищаю от {} правда как помню 1 оставался поэтому тримил вы же их просто реплайс делаете. В чем выигрышь производительности, вы так долго мучались. 2. Ваш окончательный вариант содержит 3 регулярки а по вашему утверждению регулярка зло которое сильно тормозит. Я не считаю их злом а в некоторых случаях что бы не плодить километры кода они незаменимы. Просто интересно с чем связано отказ от варианта без регулярок?
да, давайте разберемся 1) последний вариант который Вы предложили - вот Код (PHP): function getRandomAnswer($data){ $answers = explode('|', $data[1]); return $answers[rand(0, count($answers) -1)]; } $str = "{{Привет|Здравствуйте|Добрый день} Александр!|{Хороший|Великолепный} день Александр!}"; $rand_answers = preg_replace_callback('/{+(.*?)}+/', 'getRandomAnswer', $str); $answer = explode("|", $rand_answers); echo trim($answer[rand(0, count($answer) -1)], '}'); давайте скормим ему строку да, отработает нормально, но меня смутила регулярка, ведь в данном случае можно обойтись без нее, поэтому я и предложил вариант без регулярки Код (PHP): $str = "{{в1|в2}|{в3|{в10|в11|в12}|{в101|{в222|в333|в444}|в123}|{в13|в14|в15}}|{в6|в7}} александр"; $end_pos = strrpos($str, '}'); $before = substr($str, 0, $end_pos); $end = substr($str, $end_pos+(substr($str, $end_pos, 1)=='}'?1:0)); $before = str_replace(array('}','{'), '', $before); $arr = explode('|', $before); echo $arr[array_rand($arr)].$end; да, отличается только отсутствием регулярки, тк она тут и не нужна.... давайте скормим моему и Вашему варианту строку но если скормить и моему и Вашему варианту строку то и мой и Ваш сожрет бОльшую часть строки именно поэтому я далее написал, что если хочется чего-то более сложного, то да, нужна регулярка и привел следующий пример Код (PHP): $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; тут уже нет привязки к позиции и количеству {} относительно текста далее я, немного подумав, решил ввести поддержку {}| прямо в тексте и предложил такой вариант Код (PHP): $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>'; тут вообще нет привязки ни к позиции {} ни к их количеству и можно использовать {}| в тексте как видите, чем больше условий, тем больш используются регулярки 2) я ни в коем случае не говорю что регулярки это зло. я люблю регулярки, просто считаю что их не нужно использовать там где можно обойтись и без них так что всё логично
Код (PHP): function getRandomAnswer($data){ $answers = explode('|', $data[1]); return $answers[rand(0, count($answers) -1)]; } $str = "{{Привет|Здравствуйте|Добрый день} Александр!|{Хороший|Великолепный} день Александр!}"; $rand_answers = preg_replace_callback('/{+(.*?)}+/', 'getRandomAnswer', $str); $answer = explode("|", $rand_answers); echo trim($answer[rand(0, count($answer) -1)], '}'); вот это работает не верно (в принципе по этому я писал что не понимаю как оно работает и будут над этим думать) есть взять такую строчку: Код (PHP): $str = 'Привет {{Виктор|{Антон|Антонио|Антошка}|Сергей}|{Господин|Сэр|Товарищ}} как {твои|ваши} дела'; то часть кода жрет, т.е. выводит такое: а где как дела? все что не попадает между { и } должно быть в тексте.
до собственно любое мероприятие по парсингу чего-либо жрет памяти больше чем привыкли ) и это еще не полноценный лексический анализатор(с проверкой на правильность синтаксиса, разбором на лексемы и тд и тп) )) поэтому и предложено несколько вприантов плюс ко всему, строка перебирается не php-конструкциями типа while, for и тд, а нативной C-шной библиотекой регулярок, поэтому тут уже расход памяти зависит только от правильно составленной регулярки и количества текста который надо обработать
Бугага VLK если хочешь выжить в мире программирования учись думать а не копировать! Копирование приводит к плохим результатам. Ты вообще то не понимал как работать с preg_replace_callback как его здесь можно применить, я не думал 2 дня не оптимизировал я для примера в онлайн редакторе накидал код для парсинга твоего первоначального примера и он работает. Дал бы тот что с как {твои|ваши} дела может я пошел бы другим путем. Цель у меня была не написать и продумать детали за тебя а дать толчек что ты начал думать и писать самостоятельно. Да ладно я не в упрек написал, просто вы так начали хорошо, регулярки плохо сейчас без них напишу а в результате 3 регулярке в конечном варианте. Вот я немного и разочаровался.
Хмм, давай начнем с того что требовалось сделать через регулярку, да и что говорить сами понимаете что это легче сделать через регулярные выражения а не плодить кучу кода, к чему в конечном счете вы и пришли. Ну я думаю от одной регулярки ничего ужасного не произойдет, мы же не парсим Войну и Мир, не тестировал но на среднем тексте думаю разница будет не сильно заметна между моим кодом и твоим без регулярок. Но в итоге признайтесь ваш вариант с 4 регулярками а на деле вызываться будет гораздо больше раз ну с точки зрения бестродействия как то не очень. В том случае где я использовал считаю не критичным.
5 строк кода это куча кода? я же сказал, что каждый враиант заточен под свою задачу первый вариант без регулярок(аналог Вашему) - под совсем простые предложения работает быстро, жрет мало, но минус в том, что он не гибкий второй вариант с регулярками - для нескольких вхождений {...} в строке с любой глубиной работает быстро, но до сих пор не поддерживает {}| в тексте третий вариант с тоже с регулярками - позволяет обрабатывать любую последовательность и поддерживает {}| в тексте да, занимает больше времени и памяти за счет того, что может больше чем предыдущие 2 варианта началось-то всё с того, что я просто предложил вариант аналогичный Вашему, но без регулярок вот и всё
вот моих 2 варианта: вариант без поддержки {, } и | в тексте Код (PHP): $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); $str.'<br>'; плюсы: - высокая скорость на любых объемах - поддержка любых форматов текста(с очень небольшой оговоркой) минусы: - не поддерживает знаки {, } и | внутри текста - оговорка 1: между рядом стоящими {...}{...} нужно вставлять хотя бы пробел. оговорка 2: в конце текста надо вставлять пробел вариант с поддержкой {, } и | в тексте Код (PHP): $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>'; плюсы: - высокая скорость на больших объемах - поддерживает знаки {, } и | внутри текста - поддерживает любой формат текста(даже рядом стоящие {...}{...}) минусы: - маленькая скорость на мелких выражениях вот тестовые тексты: Код (PHP): $source = '{Привет|Здравствуйте|Добрый день} Александр!'; $source = 'Привет {{Виктор|{Антон|Антонио|Антошка}|Сергей}|{Господин|Сэр|Товарищ}} как {твои|ваши} дела'; $source = 'В языке {{C++|C}|{JavaScript|PHP}|C#|Java} блоки кода можно объединять в фигурные скобки, например \{{ВАШ КОД|КАКОЙ-ТО КОД};\}<br>Условия записываются так {if(1)|if(1\|\|0)}{\{do_something();\}|\{do_some_work();\}}';
Я мыслю глобально здесь пять строчек там пять строчек еще где то в итого много кода. Не обращай внимание если я не вижу особой пользы пытаюсь писать поменьше кода. Да не напрягайтесь так Просто было весело когда я прочитал ваше первое сообщение что регулярки тормозят а в конце увидел вообще жесть Да что крутого? YSandro считаю правильно предложил а эта куча вложений только все усложняет. До сих пор не понимаю зачем рамдомно выбирать между значениями. Что он там делает хз...
тогда речь шла про простой вариант текста так никто же и не спорит что формат довольно странный(хотя смотря с какой стороны посмотреть), и что при упрощении формата, регулярки и не понадобились бы. но если бы у ТС была возможность упростить формат, он бы так и сделал, я думаю... но в данном случае, время бы могло уходить на выборку данных для подстановки. из базы например... да нет здесь кучи вложений. тут вызов 5 нативных функций и только в preg_replace_callback есть одного вложение, ито оно не рукерсивное ладно, а то сейчас как обычно какой-нибудь холи вар начнется о "правильном" использовании регулярок
это уже второй вопрос. в случае шаблонного синтаксиса с переменными, надо где-то хранить и откуда-то брать значения этих переменных.