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, что корректно отрабатывало

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

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

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

 8888888888P  Y88b   d88P    888888   d888   
d88P Y88b d88P "88b d8888
d88P Y88o88P 888 888
d88P Y888P 888 888
d88P 888 888 888
d88P 888 888 888
d88P 888 88P 888
d8888888888 888 888 8888888
.d88P
.d88P"
888P"
Зарегистрируйтесь для добавления материалов без проверки.