2

I have a scenario that I think requires some kind of recursive iterations, but I am not certain, and not being an expert on recursive coding, I am drawing a blank.

Here is the scenario:

I have a phrase something like this:

[He|She] would [like|love|hate] to [Play Golf|Play Tennis|Play Baseball] Today.

I would like PHP to parse through that phrase (each section inside [] brackets represents possible variations for that word or phrase, each possibility separated by a | pipe), and generate all variations, so for example, the above would return:

He would like to Play Golf Today. 
He would like to Play Tennis Today.
He would like to Play Baseball Today.
He would love to Play Golf Today.
He would love to Play Tennis Today.
He would love to Play Baseball Today.
He would hate to Play Golf Today.
He would hate to Play Tennis Today.
He would hate to Play Baseball Today.
She would like to Play Golf Today.
She would like to Play Tennis Today.
She would like to Play Baseball Today.
She would love to Play Golf Today.
She would love to Play Tennis Today.
She would love to Play Baseball Today.
She would hate to Play Golf Today.
She would hate to Play Tennis Today.
She would hate to Play Baseball Today.

I am trying to figure out how to write PHP code to take the inputted phrase, and return all possible sentences.

asked Jul 27, 2013 at 20:37
4
  • finite state machine to parse the phrase and generate all the sentences? Commented Jul 27, 2013 at 20:38
  • For my purposes, I guess we can put a limit of 10 possible items per [] group, and 10 total 'pieces' to the sentence (each piece can be a singular value, or a [] group). Does that answer? Commented Jul 27, 2013 at 20:41
  • I think, it's possible to do for arbitrary number of items per group Commented Jul 27, 2013 at 20:42
  • What you want to do is find the cartesian product of the possible inputs, after which it is trivial to generate the output you want with a simple foreach. There are several good ways to do this (including an answer of my own) here: stackoverflow.com/questions/6311779/…. If you need more guidance on how to do this I can expand into an answer. Commented Jul 27, 2013 at 22:43

4 Answers 4

1

Here is a recursive solution:

<?php
function generator($input, &$result)
{
 $matches = array();
 if (preg_match('/\[(.*?)\]/', $input, $matches))
 {
 $words = explode('|', $matches[1]);
 $n = count($words);
 for ($i = 0; $i < $n; ++$i)
 {
 $input1 = str_replace($matches[0], $words[$i], $input);
 generator($input1, $result);
 }
 }
 else
 {
 $result[] = $input;
 }
}
$input = '[He|She] would [like|love|hate]';
$result = array();
generator($input, $result);
var_dump($result);

Prints 2*3 = 6 combinations:

array(6) {
 [0]=>
 string(13) "He would like"
 [1]=>
 string(13) "He would love"
 [2]=>
 string(13) "He would hate"
 [3]=>
 string(14) "She would like"
 [4]=>
 string(14) "She would love"
 [5]=>
 string(14) "She would hate"
}

I wanted to use yeild, but my php version (5.4.7) is too old for it.

answered Jul 27, 2013 at 21:51
2
  • Thanks! This is exactly what I was looking for (especially the generator() function)! Commented Jul 28, 2013 at 4:43
  • @OneNerd After I got up from sleep, I realized, how to improve the function. Take a look: I got rid of is_null check. Commented Jul 28, 2013 at 6:00
0

First of all you have to split the input string and rewrite it as an array. This will have an output like this: (I would use strpos, regexp and/or explode to split all parts)

Array(
 [0]=> Array(
 [0] => 'He',
 [1] => 'She'),
 [1]=> Array(
 [0] => ' would '),
 [2]=> Array(
 [0] => 'like',
 [1] => 'love',
 [2] => 'hate'),
...
)

After you have to loop through the array and build all combinations and store them into strings. This will look like this

//this is for tracking the progress
for($x = 0; $x < count($array_parts); $x++)
{
 //starting all at the first option
 $array_tracker[$x] = 0;
}
while(true)
{
 //build selected possibility
 $ouput_string = "";
 for($x = 0; $x < count($array_parts); $x++)
 {
 $ouput_string .= $array_parts[$x][$array_tracker[$x]];
 }
 $output_strings[] = $output_string;
 //navigate to next possibility
 for($x = count($array_parts) - 1; $x >= 0; $x--)
 {
 $array_tracker[$x]++;
 if($array_tracker[$x] == count($array_parts[$x))
 {
 $array_tracker[$x] = 0;
 }
 else
 {
 break;
 }
 if($x == 0)
 {
 //all option are done, than end this 'endless' loop
 break 2;
 }
 }
}
answered Jul 27, 2013 at 22:15
0
$string = '[He|She] would [like|love|hate] to [Play Golf|Play Tennis|Play Baseball] Today.';
$parts = explode("]", $string);
$newparts = array();
$loops = array();
foreach($parts as $part){
 if(strpos($part, '[') !== false){
 $part = preg_replace("#([^\[]+)?\[#", "", $part);
 $loops[] = explode("|", $part);
 }
}
//matching other words
$words = preg_replace("#\[(.*?)\]#", '', $string);
$words = preg_replace("#\s+#", '|', trim($words));
$words = explode("|", $words);
foreach($loops as $key => &$val){
 foreach($val as &$word){
 $word = $word.' '.$words[$key];
 }
}
$data =array();
$eval = '
 $data =array();
 ';
$eval_blocks = '';
$eval_foreach = '';
$eval_data = '
$data[] = ';
$looplength = count($loops);
for($i=0; $i<$looplength; $i++){
 $eval_foreach.= '
 foreach($loops['.$i.'] as $val'.($i+1).'){
 ';
 if( ($i+1) == $looplength ){
 $eval_data .= ' $val'.($i+1).';';
 }else{
 $eval_data .= ' $val'.($i+1).' ." ".';
 }
 $eval_blocks .= '
 }
 ';
}
$eval = $eval. $eval_foreach . $eval_data . $eval_blocks;
echo "<hr>";
print_r($words);
print_r($loops);
print_r($data);

Output:

Array
(
 [0] => would
 [1] => to
 [2] => Today.
)
Array
(
 [0] => Array
 (
 [0] => He would
 [1] => She would
 )
 [1] => Array
 (
 [0] => like to
 [1] => love to
 [2] => hate to
 )
 [2] => Array
 (
 [0] => Play Golf Today.
 [1] => Play Tennis Today.
 [2] => Play Baseball Today.
 )
)
Array
(
 [0] => He would like to Play Golf Today.
 [1] => He would like to Play Tennis Today.
 [2] => He would like to Play Baseball Today.
 [3] => He would love to Play Golf Today.
 [4] => He would love to Play Tennis Today.
 [5] => He would love to Play Baseball Today.
 [6] => He would hate to Play Golf Today.
 [7] => He would hate to Play Tennis Today.
 [8] => He would hate to Play Baseball Today.
 [9] => She would like to Play Golf Today.
 [10] => She would like to Play Tennis Today.
 [11] => She would like to Play Baseball Today.
 [12] => She would love to Play Golf Today.
 [13] => She would love to Play Tennis Today.
 [14] => She would love to Play Baseball Today.
 [15] => She would hate to Play Golf Today.
 [16] => She would hate to Play Tennis Today.
 [17] => She would hate to Play Baseball Today.
)

Update: the loop dynamically created.

DEMO: http://codepad.org/eeQd9S0r

answered Jul 27, 2013 at 22:40
0

Recursive function for generating the combinations:

function combix($items, $combos=array()){
 $res = array();
 $next = array_shift($items);
 if (is_array($next)){
 if (empty($combos)){
 return combix($items, $next);
 }
 foreach ($combos as $key => $value){
 foreach ($next as $key2 => $value2){
 if (is_array($value)){
 $res[] = array_merge($value, array($value2));
 } else {
 $res[] = array($value, $value2);
 }
 }
 }
 return combix($items, $res);
 } else {
 return $combos;
 }
}

Text processing:

$str = '[He|She] would [like|love|hate] to [Play Golf|Play Tennis|Play Baseball] Today.';
$pattern = '#\[([\w\s|]+)]#';
if (preg_match_all($pattern, $str, $matches)){
 $template = preg_replace($pattern, '%s', $str);
 $mix = array();
 foreach ($matches[1] as $key => $value){
 $mix[] = explode('|', $value);
 }
 $res = combix($mix);
 $out = array();
 foreach ($res as $key => $value){
 array_unshift($value, $template);
 $out[] = call_user_func_array('sprintf', $value);
 }
} else {
 $out = array($str);
}
print_r($out);
answered Jul 28, 2013 at 3:01
1
  • Any way (using your code) to account for more or less that 3 [] bracketed work groups in the string? Commented Jul 28, 2013 at 4:08

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.