PHP: Converting Numbers into English

9 10 2017

Flickr: By Maureen Barlin

Here’s a fun interview question for which you may wish to prepare. Create a PHP script to express integers ranging from 1-9999 in English.

There are two approaches you may take, one being smart and the other savvy. The smartest approach is to analyze, think and find the logic to meet this challenge — that way you will learn a lot, nice if you can spare the time.

Being savvy may be the better option if expediency is the greater concern.  If you take this route,  then it helps if you are familiar with Open Source repositories and know more than one programming language. Though I prefer to figure out a solution myself, owing to time constraints, I’ve opted to be savvy instead.  

The following script is the result of selecting parts of two scripts, one in Perl and the other in C, translating them into PHP, while adding my own modifications.

Perl may be old-fashioned but it still is powerful and flexible. What struck me, while perusing the Perl source code, is that years ago it had features that PHP has only recently acquired, such as array destructuring. Apparently, popularity does not equate with necessarily better, only more popular!

Here is the result of my efforts:

<?php  
$h = "";
$rest = "";  

$D = [0 => "zero","one", "two", "three", "four", "five",
"six", "seven", "eight", "nine", "ten", "eleven", "twelve",
"thirteen", "fourteen", "fifteen", "sixteen", "seventeen",
"eighteen","nineteen", "twenty", 30 => "thirty", 40 => "forty",
50 => "fifty", 60 => "sixty",70 => "seventy",80 => "eighty",
90 => "ninety"];

function validate($x, $len) {
   $retval = null;

   if (!isset($x)){
        echo "\$x is unset\n";
        $retval = false;
   }
   else
   if (is_float($x) ){
      echo "Floats are unsupported in this version.\n";
      $retval = false;
   }
   else
   if ( $len == 0)  {
      echo "Empty value\n";
      $retval = false;
   }
   else
   if ( $x < 0) { 
        echo "Negative numbers are currently unsupported.\n";
        $retval = false;
    }
    else
    if ($len > 4) {
        echo "Numbers with more than 4 digits are unsupported\n";
        $retval = false;
   }
   else {
     $retval = true;
   }
   return $retval;
}

function num2en( $x, $words) {
     $len = strlen($x);  // Get number of digits in given number
     $retval = null;

   if( validate($x, $len) === false) {
      return false;
   }

  // handle number by length and digit(s)
  switch($len)
  {
  case 1:
          $retval = "$words[$x]\n";
          break;
  case 2:
          if ( isset($words[$x]) ) {
             $retval = "$words[$x]\n";
          }
          else
          if( preg_match('/^(.)(.)$/', $x, $matches ) ){
              $retval =  $words[ $matches[1] . '0'].'-'
              . $words[ $matches[2]]."\n";
          }
          break;
  case 3:
          preg_match('/^(.)(..)$/',$x,$matches );
          [$h, $rest] = [ $words[$matches[1]] 
          . " hundred", $matches[2] ];
          if ( strcmp( $rest,'00') === 0 ) {
              $retval = $h;
          }
          if ($h == '0') {
              $retval = "and " . num2en(0 + $rest, $words);
          }
          $retval = $h . " and ". num2en( 0 + $rest, $words);
          break;
  case 4:
        $firstDigit=preg_split("//",$x,-1,PREG_SPLIT_NO_EMPTY )[0]
        $retval = $words[$firstDigit]." thousand " 
        . num2en(substr($x,1,3), $words);
        break;
  }
  return $retval;
}

//Testing:
$bla;
echo @num2en( $bla, $D );
echo num2en( -13, $D );
echo num2en( 1.5, $D );
echo num2en( 1, $D );
echo num2en( 10, $D );
echo num2en( 101, $D );
echo num2en( 1203, $D);
echo num2en( 9999, $D);
echo num2en( 19999, $D);

See live code

Note, to get the digit representing “thousands”, the code uses preg_split() despite this function requiring a string subject. Yet, the function ably handles the integer parameter. Internally, the C-source code silently converts the integer’s value to a string (see ext/pcre/php_pcre.c). That string then splits into an array of component digits, by providing the function a limit parameter of -1 as well as a fourth parameter PREG_SPLIT_NO_EMPTY. Dereferencing the array permits the code to detect the zeroth element and assign it to $firstDigit.

This example derives the PERL module “Lingua::EN::Numbers” available at CPAN and : C source code at geeksforgeeks.org.

This work is licensed under a Creative Commons License

 

Advertisements

Actions

Information

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

w

Connecting to %s




%d bloggers like this: