БлогNot. Простой генератор текста с помощью цепей Маркова

Простой генератор текста с помощью цепей Маркова

Вот здесь мы делали на C++ достаточно сложный проект для генерации текста с помощью цепей Маркова, на днях понадобилось что-то попроще, приведу мини-проект из одной функции на PHP.

Обычно подобная программа для цепей Маркова разбивает входной текст на цепочку токенов-слов, затем, перемещаясь по ним в некотором окне фиксированного размера, сохраняет первые $keySize слов в качестве префикса, и добавляет ($keySize+1)-ое слово, выбранное из набора соответствующих префиксу суффиксов.

Конечно, пределов совершенству нет, и мы вполне могли делать первые буквы предложений большими, убирать лишние знаки препинания и т.п., но всё это сразу же усложнило бы код. Путь к написанию подобного проекта можно посмотреть, например, на этой странице.

Скрипт выполнялся на локальном хосте XAMPP с PHP 8.X, исходный файл data.txt ("Колобок") также прикреплён ниже.

<?php
function markovChainTextGenerator ($text, $keySize, $maxWords) { 
                                  //текст, размер ключа в словах, общее кол-во слов
 $maxlen = 30; //макс. длина слова

 //Создать массив токенов:
 $token = [];
 $position = 0;
 $maxPosition = mb_strlen ($text, 'UTF-8');
 while ($position < $maxPosition) {
  if (preg_match('/^(\S+)/', mb_substr($text, $position, $maxlen, 'UTF-8'), $matches)) {
   $token[] = $matches[1];
   $position += mb_strlen($matches[1], 'UTF-8');
  }
  elseif (preg_match('/^(\s+)/', mb_substr($text, $position, $maxlen, 'UTF-8'), $matches)) {
   $position += mb_strlen($matches[1], 'UTF-8');
  }
  else {
   die(
    'Неизвестный токен в позиции ' . $position . ': ' . 
    mb_substr($text, $position, $maxlen, 'UTF-8') . '...' . PHP_EOL);
  }
 }

 //Создать словарь:
 $dictionary = [];
 for ($i = 0; $i < count($token) - $keySize; $i++) {
  $prefix = '';
  $separator = '';
  for ($c = 0; $c < $keySize; $c++) {
   $prefix .= $separator . $token[$i + $c];
   $separator = '.';
  }
  $dictionary[$prefix][] = $token[$i + $keySize];
 }

 //Начальный токен:
 function getStartToken(&$token,$keySize) {
  $rand = rand (0, count($token) - $keySize);
  $startToken = [];
  for ($c = 0 ; $c < $keySize ; $c++) {
   array_push ($startToken, $token[$rand + $c]);
  }
  return $startToken;
 }

 //Создать текст:
 $startToken = getStartToken($token,$keySize);
 $text = implode(' ', $startToken);
 $words = $keySize;
 do {
  $tokenKey = implode ('.', $startToken);
  if (!array_key_exists($tokenKey,$dictionary)) {
   $startToken = getStartToken ($token,$keySize);
   continue;
  }
  else {
   $rand = rand (0, count($dictionary[$tokenKey]) - 1);
   $newToken = $dictionary[$tokenKey][$rand];
  }
  $text .= ' ' . $newToken;
  $words++;
  array_shift ($startToken);
  array_push ($startToken, $newToken);
 } while ($words < $maxWords);
 return $text;
}
 
srand(time());
$text = markovChainTextGenerator(
 file_get_contents(__DIR__ . '/data.txt'), 3, 300);
echo wordwrap ($text, 100, '<br>'.PHP_EOL) . PHP_EOL;
?>

 Файл data.txt, кодировка Юникода UTF-8 (4 Кб)

Пример вывода скрипта:

ушёл, Я от волка ушёл, От тебя, зайца, не хитро уйти! И
покатился себе дальше; только волк его и видел!..
Катится колобок, а навстречу ему лиса: «Здравствуй,
колобок! Какой ты хорошенький». А колобок запел: Я по
коробу скребён, По сусеку метён, На сметане мешон, Да в
масле пряжон, На окошке стужон; Я от дедушки ушёл, Я от
бабушки ушёл, Я от зайца ушел, От тебя, волка, не хитро
уйти! И опять укатился; только медведь его и видел!..
Катится колобок, а навстречу ему медведь: «Колобок,
колобок! Я тебя съем». — «Не ешь меня, серый волк! Я тебе
песенку спою!» Я по коробу скребён, По сусеку метён, На
сметане мешон, Да в масле пряжон. На окошке стужон; Я от
дедушки ушёл, Я от волка ушёл, От тебя, лиса, и подавно
уйду! «Какая славная песенка! — сказала лиса. — Но ведь
я, колобок, стара стала, плохо слышу; сядь-ка на мою
мордочку да пропой еще разок погромче». Колобок
вскочил лисе на мордочку и запел ту же песню. «Спасибо,
колобок! Славная песенка, еще бы послушала! Сядь-ка на
мой язычок да пропой в последний разок», — сказала
лиса и высунула свой язык; колобок прыг ей на язык, а
лиса — ам его! и скушала. бабушки ушёл, Я от зайца ушёл,
Я от зайца ушёл, Я от зайца ушёл, Я от зайца ушёл, Я от
бабушки ушёл, Я от зайца ушёл, Я от бабушки ушёл, Я от
зайца ушёл, Я от бабушки ушёл, Я от зайца ушёл, Я от
бабушки ушёл, Я от зайца ушёл, Я от бабушки ушёл, Я от
зайца ушел, От тебя, волка, не хитро уйти! И покатился
себе дальше; только заяц его и видел!.. Катится колобок,
а навстречу ему заяц: «Колобок, колобок! Я тебя съем». —
«Не ешь меня, серый волк! Я тебе песенку спою», — сказал
колобок и запел: Я по коробу 

20.11.2021, 08:08 [948 просмотров]


теги: программирование textprocessing random php

К этой статье пока нет комментариев, Ваш будет первым