Convert Numbers to Words with PHP
I was recently asked the best way to convert a number to its textual form using PHP. For example, how to convert the number 123 to the string “one hundred and twenty-three”.
There is no built in PHP function to handle this, and the examples I found online tended to be too limited in some way or another, so I decided to write my own.
This function can accept numbers up to the system’s int size (2147483647 on 32-bit systems and 9223372036854775807 on 64-bit systems), both positive and negative, and can also handle real numbers (albeit with the inherent rounding inaccuracies involved in storing base 10 real numbers using base 2).
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 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | function convert_number_to_words($number) { $hyphen = '-'; $conjunction = ' and '; $separator = ', '; $negative = 'negative '; $decimal = ' point '; $dictionary = array( 0 => 'zero', 1 => 'one', 2 => 'two', 3 => 'three', 4 => 'four', 5 => 'five', 6 => 'six', 7 => 'seven', 8 => 'eight', 9 => 'nine', 10 => 'ten', 11 => 'eleven', 12 => 'twelve', 13 => 'thirteen', 14 => 'fourteen', 15 => 'fifteen', 16 => 'sixteen', 17 => 'seventeen', 18 => 'eighteen', 19 => 'nineteen', 20 => 'twenty', 30 => 'thirty', 40 => 'fourty', 50 => 'fifty', 60 => 'sixty', 70 => 'seventy', 80 => 'eighty', 90 => 'ninety', 100 => 'hundred', 1000 => 'thousand', 1000000 => 'million', 1000000000 => 'billion', 1000000000000 => 'trillion', 1000000000000000 => 'quadrillion', 1000000000000000000 => 'quintillion' ); if (!is_numeric($number)) { return false; } if (($number >= 0 && (int) $number < 0) || (int) $number < 0 - PHP_INT_MAX) { // overflow trigger_error( 'convert_number_to_words only accepts numbers between -' . PHP_INT_MAX . ' and ' . PHP_INT_MAX, E_USER_WARNING ); return false; } if ($number < 0) { return $negative . convert_number_to_words(abs($number)); } $string = $fraction = null; if (strpos($number, '.') !== false) { list($number, $fraction) = explode('.', $number); } switch (true) { case $number < 21: $string = $dictionary[$number]; break; case $number < 100: $tens = ((int) ($number / 10)) * 10; $units = $number % 10; $string = $dictionary[$tens]; if ($units) { $string .= $hyphen . $dictionary[$units]; } break; case $number < 1000: $hundreds = $number / 100; $remainder = $number % 100; $string = $dictionary[$hundreds] . ' ' . $dictionary[100]; if ($remainder) { $string .= $conjunction . convert_number_to_words($remainder); } break; default: $baseUnit = pow(1000, floor(log($number, 1000))); $numBaseUnits = (int) ($number / $baseUnit); $remainder = $number % $baseUnit; $string = convert_number_to_words($numBaseUnits) . ' ' . $dictionary[$baseUnit]; if ($remainder) { $string .= $remainder < 100 ? $conjunction : $separator; $string .= convert_number_to_words($remainder); } break; } if (null !== $fraction && is_numeric($fraction)) { $string .= $decimal; $words = array(); foreach (str_split((string) $fraction) as $number) { $words[] = $dictionary[$number]; } $string .= implode(' ', $words); } return $string; } |
Example usage:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | echo convert_number_to_words(123456789); // one hundred and twenty-three million, four hundred and fifty-six thousand, seven hundred and eighty-nine echo convert_number_to_words(123456789.123); // one hundred and twenty-three million, four hundred and fifty-six thousand, seven hundred and eighty-nine point one two three echo convert_number_to_words(-1922685.477); // negative one million, nine hundred and twenty-two thousand, six hundred and eighty-five point four seven seven // float rounding can be avoided by passing the number as a string echo convert_number_to_words(123456789123.12345); // rounds the fractional part // one hundred and twenty-three billion, four hundred and fifty-six million, seven hundred and eighty-nine thousand, one hundred and twenty-three point one two echo convert_number_to_words('123456789123.12345'); // does not round // one hundred and twenty-three billion, four hundred and fifty-six million, seven hundred and eighty-nine thousand, one hundred and twenty-three point one two three four five |
It’s really very useful. Thanks a lot
Dear Karl,
It’s a great job. Thanks again and again.
Nazim!!!!!
wow u just made my job easier! thanks
SO friggin helpful! – I was looking for something like this! Thanks a BUNCH!
this is very good script ,
thanks a lot.
This is AWESOME!
Very very thanks. Simple and very useful. Hatsoff u:-)
Thanks for the great works. Keep solving this type of problem.
Two thumbs up
Great routine, thanks. Just one point, “fourty” is spelt forty. Otherwise works perfectly…
Bug. doesn’t work with “10000000000″
I have “ten billion, one hundred and fourty-seven million, four hundred and eighty-three thousand, six hundred and fourty-seven”
Sorry I understood Integer in PHP is between –2 147 483 648 and 2 147 483 647
Wow. This function is ridiculously AWESOME and SIMPLE. what a beautiful logic used.
Yes, thanks much.
its very very useful for me thank you
Pingback: jQueryを使って言葉で現金値を表示する方法は? | t1u
how to use it in excel.. i copied the entire formula and pasted in excel but nothing is been done…pls help i am a beginner in excel..
Superb conversion man…
Nice function and easy to use
Thank you! Very good script. I have very little knowledge in php.
So question what need to add / change in code to get numbers after decimal displayed as for example ‘eleven’ instead of ‘one one’?
@Andris…I had to rework this entire function because it had a lot of issues when I tried it (but thanks to the original author for the logic). One of my issues was the one you mentioned, printing the decimal digits individually, so I wrote a separate function to handle the cents.
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
global $words;
$cents = NULL;
if (strpos($amount, '.') !== false) {
list($amount, $cents) = explode('.', $amount);
$amount = number_format($amount, 2, '.', ' '); // Truncate if more than 3 decimals
if ($cents == 0) {
$cents = $words[0];
}
elseif ($cents > 0 && $cents < 21) {
$cents = $words[$cents];
}
else {
$tens = ((int) ($cents / 10)) * 10;
$units = $cents % 10;
$cents = $words[$tens];
if ($units) {
$cents .= '-' . $words[$units];
}
}
}
else {
$cents = $words[0];
}
return $cents;
}
I should probably clarify this for the above post:
$amount = $number in the original post
$words = $dictionary in the original post
Note:
I wrote the array outside of the class/function so I had to initialize it globally. You could do that or initialize it in the class construct.
@Sahil: check these links
http://support.microsoft.com/kb/213360
http://office.microsoft.com/en-us/excel-help/three-ways-to-convert-numbers-to-text-HA001136619.aspx
@Karl: +1 to you
@Karl: The conditional check for PHP_INT_MAX is not working, I think first you should go for a coarse grain checking by counting the number of digits, may be that leads somewhere?
It’s really very useful. Thanx , thank very much
Very Useful code,Thanks
its really very helpful for me.. can u plz implement the C# version of this, I will be very grateful for that.
Pingback: Anonymous
@Andris what i did was to change this part of the function
2
3
4
5
6
7
8
$string .= $decimal;
$words = array();
foreach (str_split((string) $fraction) as $number) {
$words[] = $dictionary[$number];
}
$string .= implode(' ', $words);
}
and then convert to
2
3
4
$string .= $decimal;
$string .= convert_number_to_words($fraction);
}
That seems to do the trick, its a great code. Thanks Karl for this wonderful and simple function. The people at php should adopt this code and build it into the php core functions.
This is really helpful. Thank you.
In case you want to use the function as part of a class, please note that it is recursive.
Thank you very much . very useful post. keep it up.
Brilliant! Problem arose that needed such a solution, googled, found, copied and implemented in under 5 minutes!
Many, many thanks.
how would you handle multiple values like 1 = dog 2 = cat and 1,2 equal dog,cat
thanx a lot for this code…..really useful…..:)
It is not working for me for number 117177
It is showing output as “one hundred and seventeen thousand, one hundred and seventy-seven”
Hi,
Unless I’m missing something, that is the correct output for 117177…