6

This task has already been asked/answered, but I recently had a job interview that imposed some additional challenges to demonstrate my ability to manipulate strings.

Problem: How to reverse words in a string? You can use strpos(), strlen() and substr(), but not other very useful functions such as explode(), strrev(), etc.

Example:

$string = "I am a boy"

Answer:

I ma a yob

Below is my working coding attempt that took me 2 days [sigh], but there must be a more elegant and concise solution.

Intention:

1. get number of words
2. based on word count, grab each word and store into array
3. loop through array and output each word in reverse order

Code:

$str = "I am a boy";

echo reverse_word($str) . "\n";

function reverse_word($input) {
    //first find how many words in the string based on whitespace
    $num_ws = 0;
    $p = 0;
    while(strpos($input, " ", $p) !== false) {
        $num_ws ++;
        $p = strpos($input, ' ', $p) + 1;
    }
    
    echo "num ws is $num_ws\n";
    
    //now start grabbing word and store into array
    $p = 0;
    for($i=0; $i<$num_ws + 1; $i++) {
        $ws_index = strpos($input, " ", $p);
        //if no more ws, grab the rest
        if($ws_index === false) {
            $word = substr($input, $p);
        }
        else {
            $length = $ws_index - $p;
            $word = substr($input, $p, $length);
        }
        $result[] = $word;
        $p = $ws_index + 1; //move onto first char of next word
    }
    
    print_r($result);
    //append reversed words
    $str = '';
    for($i=0; $i<count($result); $i++) {
        $str .= reverse($result[$i]) . " ";
    }
    return $str;
}

function reverse($str) {
    $a = 0;
    $b = strlen($str)-1;
    while($a < $b) {
        swap($str, $a, $b);
        $a ++;
        $b --;
    }
    return $str;
}

function swap(&$str, $i1, $i2) {
    $tmp = $str[$i1];
    $str[$i1] = $str[$i2];
    $str[$i2] = $tmp;
}
mickmackusa
  • 43,625
  • 12
  • 83
  • 136
Meow
  • 18,371
  • 52
  • 136
  • 180

4 Answers4

16
$string = "I am a boy";

$reversed = "";
$tmp = "";
for($i = 0; $i < strlen($string); $i++) {
    if($string[$i] == " ") {
        $reversed .= $tmp . " ";
        $tmp = "";
        continue;
    }
    $tmp = $string[$i] . $tmp;    
}
$reversed .= $tmp;

print $reversed . PHP_EOL;
>> I ma a yob
thetaiko
  • 7,816
  • 2
  • 33
  • 49
  • 1
    This answer is missing its educational explanation. – mickmackusa Dec 28 '21 at 09:02
  • @mickmackusa - indeed. As it's an interview question, I'm not really inclined to provide everything ;-) Also, I disagree with closing the question; it's not really a duplicate of the question you attached since he has very specific parameters attached. Nice work resurrecting a question from a decade ago -- fun. – thetaiko Jan 13 '22 at 23:05
  • 1
    No answer on Stack Overflow is EVER meant to only speak to the asker. Every answer should include an educational explanation which can empower thousands of future researchers. I do not discriminate by time of posting while I conduct my curation routines for the betterment of Stack Overflow. Old pages are used to close new questions. Old unexplained answers offer little value to new askers who actually want to learn how and why a solution works. – mickmackusa Jan 14 '22 at 05:10
2

Whoops! Mis-read the question. Here you go (Note that this will split on all non-letter boundaries, not just space. If you want a character not to be split upon, just add it to $wordChars):

function revWords($string) {
    //We need to find word boundries
    $wordChars = 'abcdefghijklmnopqrstuvwxyz';
    $buffer = '';
    $return = '';
    $len = strlen($string);
    $i = 0;
    while ($i < $len) {
        $chr = $string[$i];
        if (($chr & 0xC0) == 0xC0) {
            //UTF8 Characer!
            if (($chr & 0xF0) == 0xF0) {
                //4 Byte Sequence
                $chr .= substr($string, $i + 1, 3);
                $i += 3;
            } elseif (($chr & 0xE0) == 0xE0) {
                //3 Byte Sequence
                $chr .= substr($string, $i + 1, 2);
                $i += 2;
            } else {
                //2 Byte Sequence
                $i++;
                $chr .= $string[$i];
            }
        }
        if (stripos($wordChars, $chr) !== false) {
            $buffer = $chr . $buffer;
        } else {
            $return .= $buffer . $chr;
            $buffer = '';
        }
        $i++;
    }
    return $return . $buffer;
}

Edit: Now it's a single function, and stores the buffer naively in reversed notation.

Edit2: Now handles UTF8 characters (just add "word" characters to the $wordChars string)...

ircmaxell
  • 163,128
  • 34
  • 264
  • 314
-2

My answer is to count the string length, split the letters into an array and then, loop it backwards. This is also a good way to check if a word is a palindrome. This can only be used for regular string and numbers.

preg_split can be changed to explode() as well.

/**
 * Code snippet to reverse a string (LM)
*/

$words = array('one', 'only', 'apple', 'jobs');

foreach ($words as $d) {
    $strlen = strlen($d);
    $splits = preg_split('//', $d, -1, PREG_SPLIT_NO_EMPTY);

    for ($i = $strlen; $i >= 0; $i=$i-1) {
        @$reverse .= $splits[$i];
    }

    echo "Regular: {$d}".PHP_EOL;
    echo "Reverse: {$reverse}".PHP_EOL;
    echo "-----".PHP_EOL;
    unset($reverse);
}
Louie Miranda
  • 1,071
  • 1
  • 20
  • 36
  • While not explicitly listed in the original question, I assume that using `preg_split()` is just as prohibited as `explode()` `split()`, `mb_split()`, etc. Also, I do not endorse the error suppression operator (`@`). Why did you ignore the OP's sample string? Your samples only contain one word -- this is not the challenge. – mickmackusa Jan 15 '22 at 08:52
-3

Without using any function.

$string = 'I am a boy';

$newString = '';
$temp = '';
$i = 0;
while(@$string[$i] != '')
{
  if($string[$i] == ' ') {
     $newString .= $temp . ' ';
     $temp = '';
  }
  else {
   $temp = $string[$i] . $temp;
  }
  $i++;
}
$newString .= $temp . ' ';
echo $newString;

Output: I ma a yob

Sumit Verma
  • 75
  • 1
  • 3
  • I do not endorse the use of the stfu operator (`@`) because it indicates poor handling of non-present variables and gives the code a bad smell. This is unexplained and a near-copy of the accepted answer. – mickmackusa Jan 15 '22 at 08:50