PHP скрипт для генерации текста из шаблона

Для одного из личных проектов требовалась мне генерация текста по заданному шаблону. Да, существуют различные сервисы, десктопные программы, решающие данную задачу в полной мере. А вот готового PHP-класса я так нигде и не нашел. Поэтому пришлось изобретать свой велосипед.

Во многих программах генерации текста используются шаблоны вида: "{Добрый день|Доброе утро}! Какая {на улице|за {окном|бортом}} {прекрасная|очаровательная|великолепная} погода!". Поэтому я решил и в своем решении не отходить от классики жанра.

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

  • все завязано на цикле while, который отрабатывает до тех пор, пока не будут заменены все блоки текста между фигурными скобками "{текст|текст}";
  • на каждой итерации отыскиваются отдельные блоки текста между фигурными скобками с самым высоким уровнем вложенности;
  • все обнаруженные блоки текста заменяются плейсхолдером и помещаются в массив плейсхолдеров;
  • по завершению цикла у нас формируется сжатая строка и массив плейсхолдеров;
  • при запуске генерации текста отрабатывает рекурсивная функция, которая случайно выбирает слова из бывших блоков с фигурными скобками и заменяет плейсхолдеры на текст.

Очень тяжело излагать суть алгоритма доступными словами. Но, надеюсь, если кто-то захочет разобраться в работе класса, то эта небольшая инструкция поможет.

  1. <?php
  2. /**
  3.  * @file
  4.  * Text generation from template.
  5.  * Template example: {My|Your} {name|surname} is {Semen {Angarsky|Aleksandrov}|Alex|Dima}.
  6.  *
  7.  * @author http://www.angarsky.ru/
  8.  */
  9.  
  10. class TextTemplateGenerator {
  11.  
  12. // Text template provided by user.
  13. private $template = '';
  14. // Text template prepared for generation.
  15. private $generator = '';
  16. // Array of replacements for text generator.
  17. private $replacements = array();
  18. // Symbol that used as replacement in generator text template.
  19. private $replace_symbol = 'RPLC';
  20.  
  21. /**
  22.   * Constructor.
  23.   *
  24.   * @param string $template
  25.   * Template for text generation.
  26.   */
  27. function __construct($template = '') {
  28. $this->set_template($template);
  29. }
  30.  
  31. /**
  32.   * Sets text template for further generation.
  33.   *
  34.   * @param $template
  35.   * Template for text generation.
  36.   */
  37. public function set_template($template) {
  38. $this->template = $template;
  39. $this->prepare($template);
  40. }
  41.  
  42. /**
  43.   * Starts text generation from template.
  44.   *
  45.   * @param $count
  46.   * Number of lines to generate.
  47.   * @return string
  48.   * Generated text.
  49.   */
  50. public function generate($count) {
  51. $result = array();
  52. for ($i = 0; $i < $count; $i++) {
  53. $result[] = $this->generate_line();
  54. }
  55. return $result;
  56. }
  57.  
  58. /**
  59.   * Prepares text template for generation.
  60.   *
  61.   * Converts text template to line with replacements.
  62.   *
  63.   * @param $template
  64.   * @return string
  65.   */
  66. private function prepare($template) {
  67.  
  68. // Number of iteration for while loop.
  69. $i = 0;
  70. // ID of replacement in array.
  71. $rid = 0;
  72. $replacements = array();
  73.  
  74. // Find all sets of {a|b|c}.
  75. while (preg_match_all("/{([^{}]+)}/", $template, $matches)) {
  76.  
  77. foreach ($matches[1] as $match) {
  78. $rid++;
  79. $replace = "{" . $match . "}";
  80. $template = str_replace($replace, '_' . $this->replace_symbol . $rid . '_', $template);
  81.  
  82. // Explode match to array.
  83. $elements = explode('|', $match);
  84. foreach ($elements as $element) {
  85. $replacements[$rid][] = $element;
  86. }
  87. }
  88.  
  89. // Prevents infinite loop.
  90. if ($i++ > 100) {
  91. $template = 'INFINITE LOOP!';
  92. break;
  93. }
  94. }
  95.  
  96. $this->generator = $template;
  97. $this->replacements = $replacements;
  98. }
  99.  
  100. /**
  101.   * Generates single line of text from template array.
  102.   *
  103.   * @return string
  104.   */
  105. private function generate_line() {
  106. $result = $this->process_replacements($this->generator);
  107. return $result;
  108. }
  109.  
  110. /**
  111.   * Recursively generates text.
  112.   *
  113.   * Replaces all replacement symbols in generator text template.
  114.   *
  115.   * @param $text - text with replacements to generate.
  116.   */
  117. private function process_replacements($text) {
  118. preg_match_all('/_' . $this->replace_symbol . '([0-9]+)_/', $text, $matches);
  119. if (!empty($matches[1])) {
  120. foreach ($matches[1] as $id) {
  121. if (isset($this->replacements[$id])) {
  122. $rand = mt_rand(0, count($this->replacements[$id]) - 1);
  123. $case = $this->replacements[$id][$rand];
  124. $replace = $this->process_replacements($case);
  125. $text = str_replace('_' . $this->replace_symbol . $id . '_', $replace, $text);
  126. }
  127. }
  128. }
  129.  
  130. return $text;
  131. }
  132. }

Как генерировать текст

Указанный код необходимо поместить в файл, например TextTemplateGenerator.class.php. Далее файл необходимо подключить в вашем скрипте, после чего вы сможете использовать возможности класса. Для CMS Drupal файл может быть подключен несколькими способами:

  • добавить строку files[] = includes/TextTemplateGenerator.class.php в .info-файл модуля;
  • подключить файл в самом коде модуля.
  1. module_load_include('php', 'my_module', 'includes/TextTemplateGenerator.class');

И небольшой пример кода, демонстрирующий возможности класса по генерации текста из шаблона:

  1. $text = "{Добрый день|Доброе утро}! Какая {на улице|за {окном|бортом}} {прекрасная|очаровательная|великолепная} погода!";
  2. $generator = new TextTemplateGenerator($text);
  3. // Генерируем 5 различных вариантов текста. Результат в виде массива будет.
  4. $result = $generator->generate(5);
  5.  
  6. // Устанавливаем новый шаблон и генерируем 1 вариант текста.
  7. $new_text = "{Semen|Andrew|Alex}";
  8. $result = $generator->set_template($new_text);
  9. $result = $generator->generate(1);
  10. $output = array_shift($result);

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

Комментарии

Аватар пользователя Андрей
Андрей

Спасибо за отличный скрипт, очень помог.

Аватар пользователя Прохожий
Прохожий

Приятно видеть примеры хорошего программирования :)

Аватар пользователя Прохожий
Прохожий

Кстати, в регулярках нужно добавить модификатор u для utf8, что корректно отрабатывало

Аватар пользователя Вадим
Вадим

Ааааааааааааа...
Как все это понять???

Аватар пользователя Анд
Анд

Спасибо! Очень полезный скрипт.

Аватар пользователя nesn
nesn

Добрый день! А как это реализовать на вордпресс?

Добавить комментарий

   888888            8888888b.    .d8888b.  
"88b 888 "Y88b d88P Y88b
888 888 888 888 888
888 888 888 888 888 888
888 `Y8bd8P' 888 888 888 88888
888 X88K 888 888 888 888
88P .d8""8b. 888 .d88P Y88b d88P
888 888 888 8888888P" "Y8888P88
.d88P
.d88P"
888P"
Зарегистрируйтесь для добавления материалов без проверки.