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

41 comments

  • Ruby

    It’s really very useful. Thanks a lot :)

  • Nazim

    Dear Karl,
    It’s a great job. Thanks again and again.

    Nazim!!!!!

  • Femi

    wow u just made my job easier! thanks

  • Kyle TheJete'

    SO friggin helpful! – I was looking for something like this! Thanks a BUNCH!

  • Niraj kumar

    this is very good script ,

    thanks a lot.

  • Lucas

    This is AWESOME!

  • Tibin V Paul

    Very very thanks. Simple and very useful. Hatsoff u:-)

  • Safatullah

    Thanks for the great works. Keep solving this type of problem.

  • eleda

    Two thumbs up

  • Charles

    Great routine, thanks. Just one point, “fourty” is spelt forty. Otherwise works perfectly…

  • test

    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”

  • test

    Sorry I understood Integer in PHP is between –2 147 483 648 and 2 147 483 647

  • S Aqeel

    Wow. This function is ridiculously AWESOME and SIMPLE. what a beautiful logic used.

  • Jim D.

    Yes, thanks much.

  • saravanan

    its very very useful for me thank you

  • Pingback: jQueryを使って言葉で現金値を表示する方法は? | t1u

  • sahil

    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..

  • Jagan

    Superb conversion man… :) Nice function and easy to use :)

  • Andris

    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’?

  • Devin

    @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.

    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
        public function getCents($amount) { // Function to handle the cent words

            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;
        }
  • Devin

    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.

  • Zeeshan
  • Zeeshan

    @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?

  • Pradeep

    It’s really very useful. Thanx , thank very much :)

  • Reshma

    Very Useful code,Thanks

  • R Ahmed

    its really very helpful for me.. can u plz implement the C# version of this, I will be very grateful for that.

  • Pingback: Anonymous

  • Kebba

    @Andris what i did was to change this part of the function

    1
    2
    3
    4
    5
    6
    7
    8
    if (null !== $fraction && is_numeric($fraction)) {
            $string .= $decimal;
            $words = array();
            foreach (str_split((string) $fraction) as $number) {
                $words[] = $dictionary[$number];
            }
            $string .= implode(' ', $words);
        }

    and then convert to

    1
    2
    3
    4
    if (null !== $fraction && is_numeric($fraction)) {
            $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.

  • Leke Ojikutu

    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.

  • bharat

    Thank you very much . very useful post. keep it up.

  • Dennis

    Brilliant! Problem arose that needed such a solution, googled, found, copied and implemented in under 5 minutes!
    Many, many thanks.

  • James Beuthling

    how would you handle multiple values like 1 = dog 2 = cat and 1,2 equal dog,cat

  • Pranay

    thanx a lot for this code…..really useful…..:)

  • Jigar Dave

    It is not working for me for number 117177

    It is showing output as “one hundred and seventeen thousand, one hundred and seventy-seven”

  • Karl

    Hi,

    Unless I’m missing something, that is the correct output for 117177…

  • LeNguyen

    Thank you so much for this very useful function.

  • Geeth

    I had updates some thing like this…

    $number = 100.04
    //One Hundred cents Zero-Four Only

    $number = 100.34
    //One Hundred cents Thirty-Four Only

    $number = 100.16
    //One Hundred cents Sixteen Only

    ‘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’

    );
    $cets = array(
    01 => ‘One’,
    02 => ‘Two’,
    03 => ‘Three’,
    04 => ‘Four’,
    05 => ‘Five’,
    06 => ‘Six’,
    07 => ‘Seven’,
    08 => ‘Eight’,
    09 => ‘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’,
    );

    if (!is_numeric($number)) {
    return false;
    }

    if (($number >= 0 && (int) $number < 0) || (int) $number < 0 – PHP_INT_MAX) {
    // overflow
    trigger_error(
    'numtowords only accepts numbers between -' . PHP_INT_MAX . ' and ' . PHP_INT_MAX,
    E_USER_WARNING
    );
    return false;
    }

    if ($number < 0) {
    return $negative . numtowords(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 . numtowords($remainder);
    }
    break;
    default:
    $baseUnit = pow(1000, floor(log($number, 1000)));
    $numBaseUnits = (int) ($number / $baseUnit);
    $remainder = $number % $baseUnit;
    $string = numtowords($numBaseUnits) . ' ' . $dictionary[$baseUnit];
    if ($remainder) {
    $string .= $remainder = 11 && $fraction <= 19){
    $string .= $cets[$fraction];
    } elseif ($fraction < 09){
    $ff = preg_replace("/(?

  • Bhushan Deshmukh

    Thanx alot Karl….

  • Raman

    Hi,

    I have passed the number 100000 to the function, but the function returning the string as one hundred thousand, rather it should give one lac…
    Pls help..

  • Rob...

    Hi,

    What license have you released this code under?

    Regards,

    Rob…

  • Karl

    Hi Rob,

    No license, please use the code however you wish.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>