Ripa Saha
Ripa Saha

Reputation: 2540

need to create an random sentence from a given sentence

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}
        )
)

Upvotes: 3

Views: 1473

Answers (4)

OGHaza
OGHaza

Reputation: 4795

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

Upvotes: 0

user2314737
user2314737

Reputation: 29337

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

Upvotes: 1

Bryan Elliott
Bryan Elliott

Reputation: 4095

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

Upvotes: 0

Sam
Sam

Reputation: 20486

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"

Upvotes: 2

Related Questions