Recursive PHP Spintax Class 3.0

Posted on September 23rd, 2011

The last and final version update of the famous PHP Spintax class, this is ultimately recursive and easy to use. I hope that users online may fidn this class useful. It is free and open source, use it freely as you need. It’s simple to use read more below on how to use the Spintax Class.

How to use:

Just include the class and use the code below.

1
2
3
4
5
<?php
include("spintax.class.php");
$spintax = new Spintax;
// Add true to the spin functions to debug and see each line as it is spun in the process
$spintax->spin("{{Hello|Hi} my name is {Ron|Ronald}|Another random {sentence|{statement|phrase|saying}}}");

That’s all!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<?php
class Spintax {
   
   function spin($str, $test=false)
   {
      if(!$test){
         do {
            $str = $this->regex($str);
         } while ($this->complete($str));
         return $str;
      } else {
         do {
            echo "<b>PROCESS: </b>";var_dump($str = $this->regex($str));echo "<br><br>";
         } while ($this->complete($str));
         return false;
      }
   }
   
   function regex($str)
   {
      preg_match("/{[^{}]+?}/", $str, $match);
      // Now spin the first captured string
      $attack = explode("|", $match[0]);
      $new_str = preg_replace("/[{}]/", "", $attack[rand(0,(count($attack)-1))]);
      $str = str_replace($match[0], $new_str, $str);
      return $str;
   }
   
   function complete($str)
   {
      $complete = preg_match("/{[^{}]+?}/", $str, $match);
      return $complete;
   }
}

Bug fixes – ultimately recursive now

8 Comments on “Recursive PHP Spintax Class 3.0”

1 Recursive PHP Spintax Class 2.5 | ronald a. richardson said at 10:42 am on September 30th, 2011:

[...] is the completely true recursive renovated class that makes use of regex. Get 3.0 NOW! PHP Recursive Spintax Class 3.0 12345678910111213141516171819202122232425262728293031323334<?php class Spintax {   [...]

2 Article Manager said at 1:20 pm on October 29th, 2011:

I want to thank you from this class. It made possible to deploy my tool on site. I’m not sure how code will stick on comments here, but I will try to send you my variation of your code so you can further develop yours if needed:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
// usage: echo Spintax::process('This is {my nested {spintax|spuntext} formatted string|your nested {spintax|spuntext} formatted string} example.');
class Spintax
{
    # this is just a wrapper for shorter static calls
   function process($text, $template = array()) {
        $c = new SpintaxBase();
        if ($template) {
            array_walk($template, array($c, 'filter_template'));
            $c-&gt;template = $template;
        }
        return $c-&gt;get($text);
    }
}

// modified from: http://ronaldarichardson.com/2011/09/23/recursive-php-spintax-class-3-0/
class SpintaxBase
{
    # template left marker, separator and right marker for default spintax format
   # you can change the format by setting this variable before calling get method for example:
   # $c-&gt;template = array('[spin]', '~', '[/spin]');
   public $template = array('{', '|', '}');
    public $match_str;
     
    # sanitize template chars to work with regexp
   public function filter_template(&amp;$val) {
        $val = str_replace(array('[', ']', '/', '~'), array('\[', '\]', '\\/', '~'), $val);
    }
     
    # main getter
   public function get($text) {
        if ($text) {
            $this-&gt;match_str = '/'.$this-&gt;template[0].'[^'.$this-&gt;template[0].$this-&gt;template[2].']+?'.$this-&gt;template[2].'/';
            do {
                $text = $this-&gt;_capture($text);
            } while (preg_match($this-&gt;match_str, $text));
        }
        return $text;
    }

    private function _capture($text) {
        preg_match($this-&gt;match_str, $text, $match);
        if (isset($match[0])) {
            $words = explode($this-&gt;template[1], $match[0]);
            $replace = preg_replace('/['.$this-&gt;template[0].$this-&gt;template[2].']/', '', $words[rand(0, count($words)-1)]);
            $text = str_replace($match[0], $replace, $text);
        }
        return $text;
    }
}
3 Ronald said at 1:31 pm on October 29th, 2011:

Cool, I have already made spintax editors with syntax highlighting, a desktop version and web based version, will be sure to share soon.

4 Article Manager said at 2:57 pm on October 29th, 2011:

I’ll be watching this space closely then! Now meanwhile I did something you might be interested too, namely javascript and coffee script version of the spinner. I can’t resist to share them too as a contribution to your site. I noticed your Python version and was inspired to this port:

coffeescript:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
split_str = '|'
replace_regexp_str = /[{}]/gi
match_regexp_str = /{[^{}]+?}/gi

spin = (txt) -&gt;
   if txt
      txt = capture(txt) while txt.match(match_regexp_str)
   txt

capture = (txt) -&gt;
   match = txt.match(match_regexp_str)
   if (match[0])
      words = match[0].split(split_str)
      replace = words[Math.floor(Math.random()*words.length)].replace(replace_regexp_str, '')
      txt = txt.replace(match[0], replace)
   txt

alert spin('This is {my nested {spintax|spuntext} formatted string|your nested {spintax|spuntext} formatted string} test.')

which turns easily to javascript via http://jashkenas.github.com/coffee-script/ evaluator:

var capture, match_regexp_str, replace_regexp_str, spin, split_str;

split_str = '|';
replace_regexp_str = /[{}]/gi;
match_regexp_str = /{[^{}]+?}/gi;

spin = function(txt) {
  if (txt) {
    while (txt.match(match_regexp_str)) {
      txt = capture(txt);
    }
  }
  return txt;
};

capture = function(txt) {
  var match, replace, words;
  match = txt.match(match_regexp_str);
  if (match[0]) {
    words = match[0].split(split_str);
    replace = words[Math.floor(Math.random() * words.length)].replace(replace_regexp_str, '');
    txt = txt.replace(match[0], replace);
  }
  return txt;
};

alert(spin('This is {my nested {spintax|spuntext} formatted string|your nested {spintax|spuntext} formatted string} test.'));

One case came to my mind; are you sure replace part doesn’t replace all occurrence of one word to same synonym? Say I have a phrase “{one|two|three}{one|two|three}” would it give only: one one or two two or three three? I know, its a small test run to find out :)

5 Ronald said at 5:50 pm on October 29th, 2011:

Awesome share, I will have to make use of the JavaScript version.

Also:
The replace doesn’t work like that, the regex finds the lowest level of “{}” first then spins it then replace, and all of this happens one match at a time. So they are not all being replaced at the same time.

So the outcome will be random each spin. try it.

6 Article Manager said at 11:43 am on October 30th, 2011:

Yea, I tested and it works. No problems with deep nested sets or repeating options. Way to go, looking forward more cool stuff from this site :)

7 fransberns said at 4:49 pm on February 14th, 2012:

Ronald, Thank you for sharing this. This class is very, very useful.
But I tested and this class replace all occurrence of one word to same synonym at the same time.

This variation of your code replace one match at a time (sorry, It is not elegant but it works):

Replace the line:

1
$str = str_replace($match[0], $new_str, $str);

By the following lines:

1
2
3
4
5
6
//one match at a time
$match_0 = str_replace("|", "\|", $match[0]);
$match_0 = str_replace("{", "\{", $match_0);
$match_0 = str_replace("}", "\}", $match_0);
$reg_exp = "/".$match_0."/";
$str = preg_replace($reg_exp, $new_str, $str, 1);
8 Ronald said at 4:39 pm on February 16th, 2012:

@fransbern it actually replaces one match at time, and never all at once under any circumstance. Put it in test mode to see what I mean.


Leave a Reply

    To syntax highlight code just use [cc lang="whatever language here"]your code here[/cc]