PHP скрипт для генерации текста из шаблона
Для одного из личных проектов требовалась мне генерация текста по заданному шаблону. Да, существуют различные сервисы, десктопные программы, решающие данную задачу в полной мере. А вот готового PHP-класса я так нигде и не нашел. Поэтому пришлось изобретать свой велосипед.
Во многих программах генерации текста используются шаблоны вида: "{Добрый день|Доброе утро}! Какая {на улице|за {окном|бортом}} {прекрасная|очаровательная|великолепная} погода!". Поэтому я решил и в своем решении не отходить от классики жанра.
Какое-то время я хотел написать класс исключительно на регулярных выражениях, но у меня в полной мере это так и не получилось - пришлось делать через плейсхолдеры. В общем алгоритм работы такой:
- все завязано на цикле
, который отрабатывает до тех пор, пока не будут заменены все блоки текста между фигурными скобками "{текст|текст}";while
- на каждой итерации отыскиваются отдельные блоки текста между фигурными скобками с самым высоким уровнем вложенности;
- все обнаруженные блоки текста заменяются плейсхолдером и помещаются в массив плейсхолдеров;
- по завершению цикла у нас формируется сжатая строка и массив плейсхолдеров;
- при запуске генерации текста отрабатывает рекурсивная функция, которая случайно выбирает слова из бывших блоков с фигурными скобками и заменяет плейсхолдеры на текст.
Очень тяжело излагать суть алгоритма доступными словами. Но, надеюсь, если кто-то захочет разобраться в работе класса, то эта небольшая инструкция поможет.
- <?php
- /**
- * @file
- * Text generation from template.
- * Template example: {My|Your} {name|surname} is {Semen {Angarsky|Aleksandrov}|Alex|Dima}.
- *
- * @author http://www.angarsky.ru/
- */
-
- class TextTemplateGenerator {
-
- // Text template provided by user.
- private $template = '';
- // Text template prepared for generation.
- private $generator = '';
- // Array of replacements for text generator.
- private $replacements = array();
- // Symbol that used as replacement in generator text template.
- private $replace_symbol = 'RPLC';
-
- /**
- * Constructor.
- *
- * @param string $template
- * Template for text generation.
- */
- function __construct($template = '') {
- $this->set_template($template);
- }
-
- /**
- * Sets text template for further generation.
- *
- * @param $template
- * Template for text generation.
- */
- public function set_template($template) {
- $this->template = $template;
- $this->prepare($template);
- }
-
- /**
- * Starts text generation from template.
- *
- * @param $count
- * Number of lines to generate.
- * @return string
- * Generated text.
- */
- public function generate($count) {
- $result = array();
- for ($i = 0; $i < $count; $i++) {
- $result[] = $this->generate_line();
- }
- return $result;
- }
-
- /**
- * Prepares text template for generation.
- *
- * Converts text template to line with replacements.
- *
- * @param $template
- * @return string
- */
- private function prepare($template) {
-
- // Number of iteration for while loop.
- $i = 0;
- // ID of replacement in array.
- $rid = 0;
- $replacements = array();
-
- // Find all sets of {a|b|c}.
- while (preg_match_all("/{([^{}]+)}/", $template, $matches)) {
-
- foreach ($matches[1] as $match) {
- $rid++;
- $replace = "{" . $match . "}";
- $template = str_replace($replace, '_' . $this->replace_symbol . $rid . '_', $template);
-
- // Explode match to array.
- $elements = explode('|', $match);
- foreach ($elements as $element) {
- $replacements[$rid][] = $element;
- }
- }
-
- // Prevents infinite loop.
- if ($i++ > 100) {
- $template = 'INFINITE LOOP!';
- break;
- }
- }
-
- $this->generator = $template;
- $this->replacements = $replacements;
- }
-
- /**
- * Generates single line of text from template array.
- *
- * @return string
- */
- private function generate_line() {
- $result = $this->process_replacements($this->generator);
- return $result;
- }
-
- /**
- * Recursively generates text.
- *
- * Replaces all replacement symbols in generator text template.
- *
- * @param $text - text with replacements to generate.
- */
- private function process_replacements($text) {
- preg_match_all('/_' . $this->replace_symbol . '([0-9]+)_/', $text, $matches);
- if (!empty($matches[1])) {
- foreach ($matches[1] as $id) {
- if (isset($this->replacements[$id])) {
- $rand = mt_rand(0, count($this->replacements[$id]) - 1);
- $case = $this->replacements[$id][$rand];
- $replace = $this->process_replacements($case);
- $text = str_replace('_' . $this->replace_symbol . $id . '_', $replace, $text);
- }
- }
- }
-
- return $text;
- }
- }
Как генерировать текст
Указанный код необходимо поместить в файл, например TextTemplateGenerator.class.php. Далее файл необходимо подключить в вашем скрипте, после чего вы сможете использовать возможности класса. Для CMS Drupal файл может быть подключен несколькими способами:
- добавить строку
в .info-файл модуля;files[] = includes/TextTemplateGenerator.class.php
- подключить файл в самом коде модуля.
- module_load_include('php', 'my_module', 'includes/TextTemplateGenerator.class');
И небольшой пример кода, демонстрирующий возможности класса по генерации текста из шаблона:
- $text = "{Добрый день|Доброе утро}! Какая {на улице|за {окном|бортом}} {прекрасная|очаровательная|великолепная} погода!";
- $generator = new TextTemplateGenerator($text);
- // Генерируем 5 различных вариантов текста. Результат в виде массива будет.
- $result = $generator->generate(5);
-
- // Устанавливаем новый шаблон и генерируем 1 вариант текста.
- $new_text = "{Semen|Andrew|Alex}";
- $result = $generator->set_template($new_text);
- $result = $generator->generate(1);
- $output = array_shift($result);
Вот такой, иногда весьма полезный, скрипт у меня получился. И помните, что не всякая генерация текста может быть полезна для вашего сайта :)
Комментарии
Спасибо за отличный скрипт, очень помог.
Приятно видеть примеры хорошего программирования :)
Кстати, в регулярках нужно добавить модификатор u для utf8, что корректно отрабатывало
Ааааааааааааа...
Как все это понять???
Спасибо! Очень полезный скрипт.
Добрый день! А как это реализовать на вордпресс?
Добавить комментарий