За последние 24 часа нас посетили 62972 программиста и 1741 робот. Сейчас ищут 715 программистов ...

Возможно ли такое организовать при помощи рег. выражений

Тема в разделе "Регулярные выражения", создана пользователем VLK, 15 июн 2014.

  1. VLK

    VLK Старожил

    С нами с:
    15 дек 2013
    Сообщения:
    3.010
    Симпатии:
    58
    Смотрите, есть текст до обработки, он выглядит так:
    а после обработки, все что находится в фигурных скобках убирается и за места него вставляется один из вариантов из фигурных скобок в рандомном порядке, т.е. в результате мы получаем:
    НО!
    могут быть и более сложные варианты, вложения с вложениями, типа:
    подскажите, возможно ли подобное организовать через preg_replace или это будет геморройно?
    как я понимаю нужна регулярное выражение - $pattern, которое будет вытаскивать то, что находится в фигурных скобках, но тут проблема может возникнуть где вложения с вложениями.
    А в качестве $replacement функция которая из вариантов будет выбрать один и возвращать его, но как передавать туда эти значения.
     
  2. dapperkop

    dapperkop Активный пользователь

    С нами с:
    26 сен 2013
    Сообщения:
    890
    Симпатии:
    0
    Я думаю, тут нужна будет рекурсия и функция, которая будет определять, что строка вида "{фраза|фраза}" типа isSupaDupaString(), возвращающая булево значение...
     
  3. VLK

    VLK Старожил

    С нами с:
    15 дек 2013
    Сообщения:
    3.010
    Симпатии:
    58
    Я лично вижу 3 камня преткновения:
    1 - возможно ли составить такое рег. выражение, которое бы искало '{}' при этом что бы в '{}' больше не было '{' т.е. без вложений и разбивало на варианты.
    2 - все полученные варианты передавало в функцию и возвращало один из них (как организовать передачу).
    3 - как работает preg_replace, начинает ли оно каждый новый перебор с начала или с точки где остановилось, если с самого начала, то все ок, если с точки где остановился раньше - печально.

    и вроде как можно и без рекурсии обойтись.
     
  4. smitt

    smitt Старожил

    С нами с:
    3 янв 2012
    Сообщения:
    3.166
    Симпатии:
    65
    Зачем, что ты делаешь?
    Уверен, есть способ гораздо правильней чем то что ты выдумал.
     
  5. VLK

    VLK Старожил

    С нами с:
    15 дек 2013
    Сообщения:
    3.010
    Симпатии:
    58
    нет, тут все правильно, за место слов типа вариант_1_1 могут идти не только слова, а словосочетания, предложения, абзацы и даже целые статьи по 100 000 символов каждая

    но если Вы предложите вариант получше, буду благодарен :)
     
  6. smitt

    smitt Старожил

    С нами с:
    3 янв 2012
    Сообщения:
    3.166
    Симпатии:
    65
    Я не понял более сложный вариант.
    Там тоже рамдомно надо 1 из 5 выбрать или надо 2 выбрать 1 для первого второй вариант для чего то другого?
     
  7. VLK

    VLK Старожил

    С нами с:
    15 дек 2013
    Сообщения:
    3.010
    Симпатии:
    58
    распишу более подробно, есть такое:
    есть две статьи:
    а в самих статьях идет свое разбитие на такого рода варианты, т.е. допустим статья_1 имеет вид (т.е. за место слова статья_1 там примерно такое, это соответственно укороченный вариант):
    теперь я надеюсь ясен смысл вложений с вложениями?
     
  8. smitt

    smitt Старожил

    С нами с:
    3 янв 2012
    Сообщения:
    3.166
    Симпатии:
    65
    Ты сайт пишешь? Сайт это запрос к базе и вывод данных. Вложения в вложении которые могут быть вложенными еще раз 10. Если задумал шаблонизатор написать бери готовый.

    Давай по другому есть такое
    {{вариант_1_1|вариант_1_2}|{вариант_2_1|вариант_2_2|вариант_2_3}} Александр!
    Что должно быть в результате?

    т.е. нужны входные параметры и то как это должно выглядеть в итоге.

    Добавлено спустя 7 минут 21 секунду:
    http://php.ru/manual/function.preg-replace-callback.html
     
  9. VLK

    VLK Старожил

    С нами с:
    15 дек 2013
    Сообщения:
    3.010
    Симпатии:
    58
    Нет, это не шаблонизатор, я решил сделать спам империю и захватить интернет.

    Есть 2 текста
    1 - {Привет|Здравствуйте|Добрый день} Александр! - вариант_1
    2 - {Хороший|Великолепный} день Александр! - вариант_2

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

    задача скрипта он получает такое:
    а возвращает или выводит на экран один из вариантов ответа выше
     
  10. smitt

    smitt Старожил

    С нами с:
    3 янв 2012
    Сообщения:
    3.166
    Симпатии:
    65
    Написал по быстрому в онлайн редакторе

    Код (PHP):
    1. function getRandomAnswer($data){
    2. $answers = explode('|', $data[1]);
    3. return $answers[rand(0, count($answers) -1)];
    4. }
    5.  
    6. $str = "{{вариант_1_1|вариант_1_2}|{вариант_2_1|вариант_2_2|вариант_2_3}}";
    7. $rand_answers = preg_replace_callback('/{+(.*?)}+/', 'getRandomAnswer', $str);
    8. $answer = explode('|', $rand_answers);
    9. echo $answer[rand(0, count($answer) -1)];
    Добавлено спустя 2 минуты 38 секунд:
    А вообще можно проще
     
  11. VLK

    VLK Старожил

    С нами с:
    15 дек 2013
    Сообщения:
    3.010
    Симпатии:
    58
    О_О
    вот то что и требовалось, только есть одна ошибка, я вставил туда:
    и кода результат вторая часть т.е.:
    Хороший день Александр! или Великолепный день Александр!
    то пишет вместе со знаком '}' т.е.:
     
  12. smitt

    smitt Старожил

    С нами с:
    3 янв 2012
    Сообщения:
    3.166
    Симпатии:
    65
    Код (PHP):
    1. $str = "{{вариант_1_1|вариант_1_2}|{вариант_2_1|вариант_2_2|вариант_2_3}}";
    2. $clean_string = str_replace(array('{', '}',), '', $str);
    3. $answers = explode('|', $clean_string);
    4. echo $answers[rand(0, count($answers) -1)];
    Добавлено спустя 2 минуты 4 секунды:
    Александра тоже туда засовываешь? Хмм...
    Мда не ищешь ты легких путей...
     
  13. VLK

    VLK Старожил

    С нами с:
    15 дек 2013
    Сообщения:
    3.010
    Симпатии:
    58
    так меня Алексы и интересуют :)
     
  14. smitt

    smitt Старожил

    С нами с:
    3 янв 2012
    Сообщения:
    3.166
    Симпатии:
    65
    используй трим или измени архитектуру или доработай алгоритм.
    Мож какой то разделитель для
    поставишь?

    Добавлено спустя 1 минуту 24 секунды:
    Ну я дал направление дальше сам думай, может кто то что то посоветует лучшее. Удачи!

    Добавлено спустя 3 минуты 17 секунд:
    Зачем все в одну строку засовывать... не ты точно не ищешь легких путей.
     
  15. VLK

    VLK Старожил

    С нами с:
    15 дек 2013
    Сообщения:
    3.010
    Симпатии:
    58
    Да, большое спасибо, тут осталось только с регулярным выражение разобраться, а точнее его сделать и все будет ок.
     
  16. smitt

    smitt Старожил

    С нами с:
    3 янв 2012
    Сообщения:
    3.166
    Симпатии:
    65
    Какое еще регулярное выражение(((

    Код (PHP):
    1. function getRandomAnswer($data){
    2. $answers = explode('|', $data[1]);
    3. return $answers[rand(0, count($answers) -1)];
    4. }
    5.  
    6. $str = "{{Привет|Здравствуйте|Добрый день} Александр!|{Хороший|Великолепный} день Александр!}";
    7. $rand_answers = preg_replace_callback('/{+(.*?)}+/', 'getRandomAnswer', $str);
    8. $answer = explode("|", $rand_answers);
    9. echo trim($answer[rand(0, count($answer) -1)], '}');
    Добавлено спустя 2 минуты 46 секунд:
    Посмотрим кто что предложит:)
     
  17. VLK

    VLK Старожил

    С нами с:
    15 дек 2013
    Сообщения:
    3.010
    Симпатии:
    58
    ну я сейчас всмотрелся в код и у меня такой же вопрос возник :)


    Код работает, только я пока совсем не понимаю как, ну да ладно, буду въезжать, еще раз спасибо.
     
  18. YSandro

    YSandro Старожил

    С нами с:
    7 апр 2011
    Сообщения:
    2.523
    Симпатии:
    2
    Такой шаблон не проще было бы сделать так
    Код (PHP):
    1. $str = '{greetings}, {name}!'; 
    , а заменять эти метки функцией из массивов любой сложности? Приветствий может быть больше, на разных языках и т.п. Имён тоже.
    А то так можно в скобках запутаться (тебе или контент менеджеру), сложно выглядит.
     
  19. smitt

    smitt Старожил

    С нами с:
    3 янв 2012
    Сообщения:
    3.166
    Симпатии:
    65
    Абсолютно согласен. Рано или поздно он замучиется с многочисленными вложениями.
    Могу еще изощренней, но и этого пока хватает. Там все просто.
     
  20. s.melukov

    s.melukov Новичок

    С нами с:
    31 июл 2014
    Сообщения:
    78
    Симпатии:
    0
    может я конечно не до конца понял суть задачи топикстартера, но зачем всё усложнять?
    Код (PHP):
    1. $str = "{{в1|в2}|{в3|{в10|в11|в12}|{в101|{в222|в333|в444}|в123}|{в13|в14|в15}}|{в6|в7}} александр";
    2. $end_pos = strrpos($str, '}');
    3. $before = substr($str, 0, $end_pos);
    4. $end = substr($str, $end_pos+(substr($str, $end_pos, 1)=='}'?1:0));
    5. $before = str_replace(array('}','{'), '', $before);
    6. $arr = explode('|', $before);
    7. echo $arr[array_rand($arr)].$end;
    Добавлено спустя 19 минут 59 секунд:
    если там действительно будет куча статей, то подумайте, сколько времени уйдет на проверку по регулярке

    Добавлено спустя 23 минуты 32 секунды:
    а вот если уже совсем хочется извращений(например замена вхождений вне зависимости от позиции {.....}), вот тогда уже регулярки можно использовать
    Код (PHP):
    1. $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}} дмитрий";
    2. foreach(preg_split('#[^\|\{\}]*(\{[\s\S]+?\}[^\|\{\}]+)#', $str, -1, PREG_SPLIT_DELIM_CAPTURE|PREG_SPLIT_NO_EMPTY) as $entry)
    3. {
    4.     $end_pos = strrpos($entry, '}');
    5.     $before = substr($entry, 0, $end_pos);
    6.     $end = substr($entry, $end_pos+(substr($entry, $end_pos, 1)=='}'?1:0));
    7.     $before = str_replace(array('}','{'), '', $before);
    8.     $arr = explode('|', $before);
    9.     $str = str_replace($entry, $arr[array_rand($arr)].$end, $str);
    10. }
    11. echo $str;
    Добавлено спустя 21 минуту 46 секунд:
    в последнем примере работают как простые варианты типа:
    так и более сложные:
    Добавлено спустя 7 минут 17 секунд:
    а в первом примере(который без регулярок) подразумевается что после "дмитрий" больше нет {.....}
     
  21. s.melukov

    s.melukov Новичок

    С нами с:
    31 июл 2014
    Сообщения:
    78
    Симпатии:
    0
    чуть подправил регулярку

    Добавлено спустя 8 минут 4 секунды:
    так тоже работает
    Добавлено спустя 50 минут 29 секунд:
    если нужна более сложная логика, уместнее будет просто написать полноценный синтакситечкий анализатор НЕ на регулярках(как вариант, воспользоваться гениратором типа yacc или lex)

    Добавлено спустя 11 минут 47 секунд:
    но если всетаки использовать алгоритм с регуляркой, то я рекомендую в конец строки вставлять пробельный символ, чтобы работали вот такие обратные одиночки:
    Добавлено спустя 10 минут 32 секунды:
    в общем, подводя итог всему....
    первый вариант который я предлагал(без регулярок) подойдет если строка устроена таким образом
    но не наоборот! но вложенностей может быть любое количество
    второй вариант(с регуляркой)
    подойдет почти для любой конфгурации текста, с любым порядком и расположением {...} и текста за исключением
    между ними должно что-то быть(хотя бы пробел!)
    например
    но в любом случае, если используем вариант с регуляркой, не забываем вставлять пробел в конец строки перед обработкой чтобы работали обратки типа
     
  22. VLK

    VLK Старожил

    С нами с:
    15 дек 2013
    Сообщения:
    3.010
    Симпатии:
    58
    s.melukov я посмотрел, какие то мудреные варианты, то, что предлагает smitt попроще, покороче и как то по логичнее (хотя работает не верно - жрет текст, но ход мысли верный), в чем преимущество ваших вариантов.
     
  23. s.melukov

    s.melukov Новичок

    С нами с:
    31 июл 2014
    Сообщения:
    78
    Симпатии:
    0
    по-Вашему, вариант без регулярок и в несколько строк, мудреный? :)
    а второй вариант который я предложил(с регулярками) нужен для более сложной логики
    если Вам важно количество строк, то вот укороченный вариант первого варианта :)
    Код (PHP):
    1. $str = "{{в1|в2}|{в3|{в10|в11|в12}|{в101|{в222|в333|в444}|в123}|{в13|в14|в15}}|{в6|в7}} александр";
    2. $end = substr($str, strrpos($str, '}')+(substr($str, strrpos($str, '}'), 1)=='}'?1:0));
    3. $arr = explode('|', str_replace(array('}','{'), '', substr($str, 0, strrpos($str, '}'))));
    4. echo $arr[array_rand($arr)].$end;
    по той же логике можно и второй сократить ))))

    Добавлено спустя 2 минуты 32 секунды:
    первый без регулярок, а второй позволяет составлять почти любую конфигурацию, хоть в одну строку, хоть в несколько

    Добавлено спустя 3 минуты 30 секунд:
    выбирать Вам конечно
    я предложил, дальше дело Ваше :)
     
  24. VLK

    VLK Старожил

    С нами с:
    15 дек 2013
    Сообщения:
    3.010
    Симпатии:
    58
    Код (PHP):
    1. $str = 'Привет {{Виктор|{Антон|Антонио|Антошка}|Сергей}|{Господин|Сэр|Товарищ}} как {твои|ваши} дела'; 
    есть такая строка

    Стразу может возникнуть вопрос, зачем такое:
    Код (Text):
    1. {{Виктор|{Антон|Антонио|Антошка}|Сергей}|{Господин|Сэр|Товарищ}}
    если можно просто сделать:
    Код (Text):
    1. {Виктор|Антон|Антонио|Антошка|Сергей|Господин|Сэр|Товарищ}
    Но меня интересует вариант работы именно с таким текстом:
    Код (Text):
    1. {{Виктор|{Антон|Антонио|Антошка}|Сергей}|{Господин|Сэр|Товарищ}}
    где вложения во вложениях и вложениями погоняют :)

    Я сейчас не могу забацать решение т.к. конструктор регулярных выражений не работает ( http://php-include.ru/regulyarnye-vyrazheniya-onlain ) (вот именно сегодня что то оно не пашет)

    Как я вижу логику работы:
    Мы при помощи preg_replace_callback ищем текст который находится между { и } при этом между { и } не должно быть { т.е. без вложений, после чего найденное включая знаки { и } отправляем callback, а оно возвращает что то конкретное т.е. вот так вот:
    из 'Привет {{Виктор|{Антон|Антонио|Антошка}|Сергей}|{Господин|Сэр|Товарищ}} как {твои|ваши} дела'
    находит {Антон|Антонио|Антошка} и возвращает допустим Антонио, в итоге отредактированный текст выглядит уже так:
    'Привет {{Виктор|Антонио|Сергей}|{Господин|Сэр|Товарищ}} как {твои|ваши} дела'

    далее находит {Виктор|Антонио|Сергей} и выбирает допустим Сергей, текст выглядит уже так:
    'Привет {Сергей|{Господин|Сэр|Товарищ}} как {твои|ваши} дела'

    потом находит {Господин|Сэр|Товарищ} и выбирает Товарищ, в итоге текст выглядит так:
    'Привет {Сергей|Товарищ} как {твои|ваши} дела'

    ну а потом выбирает Товарищ и ваши и в конечный результат:
    'Привет Товарищ как ваши дела'

    PS тут всего один принципиальный вопрос, будет ли так как надо работать preg_replace_callback все же первый вариант без вложений {Антон|Антонио|Антошка} по позиции будет находиться позже тем более поздний {Сергей|Товарищ}.
     
  25. s.melukov

    s.melukov Новичок

    С нами с:
    31 июл 2014
    Сообщения:
    78
    Симпатии:
    0
    Ну так и чем Вас мой вариант не устраивает?
    Ох не понимаю я зачем Вы всё усложняете оперируя рекурсивным алгоритмами если всё что Вы сейчас описали проще сказать так: нужно выбирать рандомный вариант из {...} с вложениями вложений в относительной независимости от позиции и количества {...}.....
    Поэтому мой вопрос тот же - чем мои варианты противоречат описанной Вами логике? :)

    Добавлено спустя 2 минуты 10 секунд:
    Давайте попробуем так... Скормите Ваш пример
    варианту с регулярками и давайте посмотрим что получится, Вы скажете что Вас не устраивает и уже оттуда будем плясать.
    Я просто сейчас вне дома и под рукой нет php поэтому не могу сам проверить[/quote]