This is a little piece of code I wrote just for fun. It converts any number you enter into the equivalent in words. For example, if you pass 234832039, it will return *"two hundred thirty-four million, eight hundred thirty-two thousand thirty-nine". There is one boolean switch: $commas. This defaults to true. If set to false, no commas will be displayed.
Usage:[text]$var = new WordedNumber(mixed $number [, boolean $commas_enabled defaults true]);
echo $var->read();[/text]
The functions work by looping through the number three digits at a time. This is really cool because it's totally extensible. Just add more large number names to the $w_names array (note the leading space). This was quite a logical challenge (for me), but I finally figured it out.
Code: Select all
class WordedNumber {
private $number;
private $text;
private $w_ones = array('zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine');
private $w_tens = array(null, null, 'twenty', 'thirty', 'fourty', 'fifty', 'sixty', 'seventy', 'eighty', 'ninty');
private $w_teens = array('ten', 'eleven', 'twelve', 'thirteen', 'fourteen', 'fifteen', 'sixteen', 'seventeen', 'eighteen', 'ninteen');
private $w_name = array('', ' thousand', ' million', ' billion', ' trillion', ' quadrillion');
private $comma_index = 0;
private $name_index = false;
private $digits = 0;
private $comma_enabled;
// Parent processor
public function __construct($int, $commas=true) {
if (intval($int) == 0) {
$this->text = $this->w_ones[0];
return;
}
$this->formatInput($int);
$this->setNamePos();
$this->comma_enabled = $commas;
foreach ($this->number as $chunk) {
$chunk = array_pad($chunk, 3, 0);
$tens = $this->getTens($chunk);
$hundreds = $this->getHundreds($chunk[2]);
$this->text .= $hundreds . $tens;
}
}
// Process first two digits
private function getTens($int) {
$have_comma = ($this->comma_index > 1 && $this->comma_enabled ? ', ' : ' ');
$len = count($int);
$name = prev($this->w_name);
$result = '';
if ($int[1] == 1) {
$teen_num = $this->w_teens[$int[0]];
$result = $teen_num . $name . $have_comma;
$this->comma_index++;
$this->name_index = true;
} elseif ($int[0] > 0 || $int[1] > 0) {
$one_digit = $this->w_ones[$int[0]];
$ten_digit = $this->w_tens[$int[1]];
$have_dash = $ten_digit && $one_digit ? '-' : '';
$result = $ten_digit . $have_dash . $one_digit . $name . $have_comma;
$this->comma_index++;
$this->name_index = true;
}
return $result;
}
// Process hundred's place
private function getHundreds($int) {
$result = '';
if ($int > 0) {
$one_digit = $this->w_ones[$int];
$num_name = ($this->name_index ? '' : prev($this->w_name));
$have_comma = ($this->comma_index > 1 && !$this->name_index && $this->comma_enabled ? ', ' : ' ');
$result = $one_digit . ' hundred' . $num_name . $have_comma;
$this->comma_index++;
}
return $result;
}
// Get input ready for processing
private function formatInput($int) {
$this->number = array_map('intval', array_reverse(str_split(strval($int))));
$this->digits = count($this->number);
$this->number = array_reverse(array_chunk($this->number, 3));
}
// Set initial index position for number names
private function setNamePos() {
for ($i = 0; $i < count($this->number); $i++) {
next($this->w_name);
}
}
// Pass result up
public function read() {
return $this->text;
}
}See the array_map() in the constructor? This is the first time I've used it, and I've gotta say, it's pretty nice. Before, I had the code for whole loop. I took up way too much space, I said, "Hey, there's gotta be something for this in the manual.", looked it up, and there it was.
P.S., I've optimized/compressed the tar out of this thing, so critique at your own risk!
* Actual result
Edit: changed it, trimmed off 3 lines. Function now loops through the number forward instead of backward.
Edit 2: opened up a bit, moved the conditional statements into multiple lines where necessary
Edit 3: be sure to pass only numbers in string form, as numbers too big (as per AbraCadaver's post below) give a bad result. Thanks for pointing that out.
Edit 4: changed the format a bit to be more readable.
Edit 5: turned into class