In this article I'm presenting my solution for a very common PHP developer job interview task where it is required to create a random sentence spinning function. Input of this function is a PHP string that employs syntax telling our code where's the randomness and what are the possible substrings for each section of randomness. Basically it is required to create PHP code that's able to process strings like the following:
<?php $string = '{Please|Just} make this {cool|awesome|random} test sentence {rotate {quickly|fast} and random|spin and be random}'; ?> |
As you can probably guess the input sentence uses braces to declare sections of randomness and the pipe character to delimit substrings that should be used randomly inside their sections. Code also must be able to process nested sections of randomness.
The output should be random sentence like any of the following:
Please make this awesome test sentence rotate fast and random Please make this cool test sentence spin and be random Just make this cool test sentence rotate quickly and random Just make this awesome test sentence spin and be random |
I've seen a few people trying to use regular expressions to handle this, but since we need to support nested sections of randomness the recursive function is our best bet. So here's my PHP random sentence spinning function and the code testing it:
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 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | <?php /** * Recursive function for parsing and randomizing * given sentence. * @author Marko Martinović * * @param string $sentence Given sentence * @return string Random sentence */ function randomizer($sentence){ $rand_sentence = ''; // Split sentence into characters $char_array = str_split($sentence); // Open braces counter $br_count = 0; // Opening left brace offset $br_start = 0; // Iterate over characters foreach ($char_array as $key => $char) { switch ($char){ // Is it left brace? case '{': // Is it opening brace? if($br_count == 0){ // If it is note the offset $br_start = $key; } // Increment open braces counter $br_count++; break; // Is it right brace? case '}': // Decrement open braces counter $br_count--; // Is it closing brace? if($br_count == 0) { /* Call randomizer again to detect nested * braces in the current section. Randomizer * returns current section but without any * nested braces so we can proceed with * exploding it using | character */ $rands = explode( '|', randomizer( implode( '', array_slice( $char_array, $br_start + 1, $key - $br_start - 1 ) ) ) ); /* Store random element of current section's * | exploded array */ $rand_sentence .= $rands[array_rand($rands)]; } break; // Is it any other character? default: /* Since | is only inside {} delimited section, * if there aren't any open braces we can just store * other chracters. */ if($br_count == 0){ $rand_sentence .= $char; } } } return $rand_sentence; } $string = '{Please|Just} make this {cool|awesome|random} test sentence {rotate {quickly|fast} and random|spin and be random}'; echo randomizer($string); ?> |
As you can see I process the input string character by character storing the static part of the string and detecting braces delimited sections using simple counter. For each section of randomness I recursively call the function to do it's job treating each section as sentence on its own. I won't get into the rest of the code because it should be self explanatory.
I've also placed this little function inside a GitHub repository so feel free to express your own ideas on how to improve my solution or leave a comment if you have even better solution.