<?php
$text = "{{Great|Awesome|Fantastic|{Brilliant|{Nifty|Spiffy|{clever|cool}}}} {link|site|website|{titty bar|jail}} - {highly|thoroughly|totally} recommended|Terrible site, don't visit it}";
print_r(spin($text, 30));
function spin($text, $numToSpin=10) {
if (substr_count($text, '{') != substr_count($text, '}'))
{ // surely we're all using PHP5 by now.
throw new Exception("Number of opening and closing curly braces don't match.");
}
$i = 0;
$spun = array();
// arbitrary cut off at 1000, should be done better
while (count($spun) < $numToSpin && $i < 1000)
{
$spunText = spinText($text);
// crc32 is supposed to be faster than most. Hopefully it's collision proof enough.
// I'm not sure hashing is the best solution.
// Instead of hashing could store the keys and a boolean value then return the keys
// as an array.
$keyHash = sprintf("%u", crc32($spunText));
if (array_key_exists($keyHash, $spun))
continue;
$spun[$keyHash] = $spunText;
$i++;
}
return array_values($spun);
}
function spinText($text)
{
$i = 0;
// another arbitrary cutoff point
while ($i < 1000)
{
// There might be a better way besides assigning to temp variable then reassigning back.
// If there's a lot of text this could be costly.
// I start replacing from the inside out. The inner most nested get replaced first.
// When the text stops changing I call it quits.
$tmpText = preg_replace_callback('#{([^{}]+)}#s', pregcallback, $text);
if (strcmp($tmpText, $text) == 0)
break;
$text = $tmpText;
$i++;
}
return $text;
}
function pregcallback($matches) {
$choices = explode('|', preg_replace('#(^{|}$)#', '', $matches[1]));
return $choices[array_rand($choices)];
}
?>