3

with below sentence,

{Please|Just} make this {cool|awesome|random} test sentence {rotate {quickly|fast} and random|spin and be random}

I need to create a random() function which will give below output:-

Please make this cool test sentence rotate fast and random.
OR
Just make this random test sentence spin and be random.

I'm not sure how will I do this.

I've tried below but didn't get result.

echo spinningFunction($str);

function spinningFunction($str)
{
    $output = "";
    $pattern = "/\[.*?\]|\{.*?\}/";
    preg_match_all($pattern, $str, $match);

    $arr = array_map(function($value){
        return explode("|", $value);
    }, $match[1]);


    foreach($arr[0] as $adj)
        foreach($arr[1] as $name)
            $output.= "{$adj} make this {$name} test sentence<br />";
    return $output;
}

any help please?

EDIT:-

function spinningFunction($str)
{
    $str = preg_replace_callback('/(\{[^}]*)([^{]*\})/im', "spinningFunction", $str);
    return $str;
}

Will someone help me to achieve an array like below from above sentence:-

Array
(
    [0] => Array
        (
            [0] => {Please|Just}
            [1] => {cool|awesome|random}
            [2] => {rotate {quickly|fast} and random|spin and be random}
        )
)
Ripa Saha
  • 2,532
  • 6
  • 27
  • 51
  • You don't have any capture groups in your regexp, so `$match[1]` doesn't contain anything. You want `$match[0]`. – Barmar Jan 16 '14 at 07:11
  • Where is your random code? You're just outputting every combination. See http://stackoverflow.com/questions/4233407/get-random-item-from-array for how to pick a random element of an array. – Barmar Jan 16 '14 at 07:13
  • yes. but $match[0] also not giving me the exact 3 element in array :( – Ripa Saha Jan 16 '14 at 07:13
  • @Barmar haven't applied that yet. actually I'm not able to achieve the first step till now. :( – Ripa Saha Jan 16 '14 at 07:15
  • @Barmar please see my edited code. I was trying to use code something like that – Ripa Saha Jan 16 '14 at 07:18
  • @Barmar Please help me Sir. You have solved many of my critical questions. You can help me. please help me. I'm not able to get proper array from that sentence till now. :( – Ripa Saha Jan 16 '14 at 07:27
  • @ripa would you be willing to use another symbol for a nested set? So `{rotate [quickly|fast] and random|spin and be random}`. This wouldn't work if you want to go more than 2 deep, but will make for a simple solution. – Sam Jan 16 '14 at 07:29
  • @SamSullivan yes You can suggest. – Ripa Saha Jan 16 '14 at 07:30

4 Answers4

2

Here's a solution that requires to use the syntax {a|[b|c]} for nested sets. It also only goes one level deep manually, so there is no clean/simple recursion. Depending on your use case, this could be fine though.

function randomizeString($string)
{
    if(preg_match_all('/(?<={)[^}]*(?=})/', $string, $matches)) {
        $matches = reset($matches);
        foreach($matches as $i => $match) {
            if(preg_match_all('/(?<=\[)[^\]]*(?=\])/', $match, $sub_matches)) {
                $sub_matches = reset($sub_matches);
                foreach($sub_matches as $sub_match) {
                    $pieces = explode('|', $sub_match);
                    $count = count($pieces);

                    $random_word = $pieces[rand(0, ($count - 1))];
                    $matches[$i] = str_replace('[' . $sub_match . ']',     $random_word, $matches[$i]);
                }
            }

            $pieces = explode('|', $matches[$i]);
            $count = count($pieces);

            $random_word = $pieces[rand(0, ($count - 1))];
            $string = str_replace('{' . $match . '}', $random_word, $string);
        }
    }

    return $string;
}

var_dump(randomizeString('{Please|Just} make this {cool|awesome|random} test sentence {rotate [quickly|fast] and random|spin and be random}.'));
// string(53) "Just make this cool test sentence spin and be random."

var_dump(randomizeString('You can only go two deep. {foo [bar|foo]|abc 123}'));
// string(33) "You can only go two deep. foo foo"
Sam
  • 20,096
  • 2
  • 45
  • 71
1

You have to take care of nested matches (see recursive patterns in http://php.net/manual/en/regexp.reference.recursive.php). Try with this

function spinningFunction($str)
{

    $output = "";
    $pattern = "/{(?:[^{}]+|(?R))*}/";
    preg_match_all($pattern, $str, $match);
    print_r($match[0]);

}

$s = "{Please|Just} make this {cool|awesome|random} test sentence {rotate {quickly|fast} and random|spin and be random}";

spinningFunction($s);

Explanation of the pattern {(?:[^{}]+|(?R))*}:

{ matches the character { literally

(?:[^{}]+|(?R))* Non-capturing group
 Quantifier: Between zero and unlimited times, as many times as possible, giving back as needed [greedy]

    1st Alternative: [^{}]+
     [^{}]+ match a single character not present in the list below
     Quantifier: Between one and unlimited times, as many times as possible, giving back as needed [greedy]
     {} a single character in the list {} literally

    2nd Alternative: (?R)
     (?R) recurses the entire pattern

} matches the character } literally
user2314737
  • 27,088
  • 20
  • 102
  • 114
0

Here is what you're looking for:

Something like this:

$text = '{Please|Just} make this {cool|awesome|random} test sentence {rotate|spin) {quickly|fast} and {randomize|spin} the text';

echo 'input-text:<br />'.$text.'<br />';  //echo original string for text output purposes.

$openingConstruct = '{';
$closingConstruct = '}';
$separator = '|';

if(preg_match_all('!'.$openingConstruct.'(.*?)'.$closingConstruct.'!s', $text, $matches)){
  $find = array();
  $replace = array();

  foreach($matches[0] as $key => $match){
    $choices = explode($separator, $matches[1][$key]);
    $find[] = $match;
    $replace[]  = $choices[mt_rand(0, count($choices) - 1)]; 

    foreach($find as $key => $value){
       if(($pos = mb_strpos($text, $value)) !== false) {

       if(!isset($replace[$key])){
          $replace[$key] = '';
       }

       $text = mb_substr($text, 0, $pos).$replace[$key].mb_substr($text, $pos + mb_strlen($value));
    }
    }
}

  echo 'output-text:<br />'.$text;
}

Output:

input-text:
{Please|Just} make this {cool|awesome|random} test sentence {rotate|spin) {quickly|fast} and {randomize|spin} the text

output-text:
Just make this random test sentence rotate and randomize the text
Bryan Elliott
  • 4,055
  • 2
  • 21
  • 22
0

Here's how you could do it using as many levels of nesting as you like:

function rand_replace($str)
{
    $pattern = "/{([^{}]*)}/";
    while (preg_match_all($pattern, $str, $matches) > 0) {
        for ($i = 0; $i < count($matches[1]); $i++) 
        {
            $options = explode('|', $matches[1][$i]);
            $rand_option = $options[rand(0, count($options)-1)];
            $str = str_replace($matches[0][$i], $rand_option, $str);
        }
    }
    return $str;
}

It matches the deepest nested alternation first, randomly replaces it with one of the options, then works its way out until the entire string has been randomised.

Output from a few runs using your example input:

Just make this random test sentence rotate fast and random
Please make this random test sentence spin and be random
Please make this cool test sentence rotate fast and random
Just make this random test sentence spin and be random
Please make this awesome test sentence spin and be random
OGHaza
  • 4,795
  • 7
  • 23
  • 29