Login


Converting Numbers to Words

By Jonathan Wood on 12/29/2010
Language: C#
Technology: WinForms
Platform: Windows
License: CPOL
Views: 40,546
General Programming » Text Handling » General » Converting Numbers to Words

Demo Project Screenshot

Download Source Code Download Source Code

Introduction

Computer programs are best at working with numbers. Working with words requires a bit more work. In some case, you may need to convert numbers to words. For example, a check-writing program needs to write out the check amount using words.

The code presented in this article does just that: It converts a floating-point value to words. The output is suitable for a check-writing program but could easily be adapted for other uses.

Presenting the Code

Listing 1 shows my NumberToText class. It's a simple class with some lookup tables and one method, Convert, which performs the conversion from a Decimal data type to English words.

The Convert method starts by converting the value into a string without the fractional portion. It then loops through the digits in this string in reverse order (the last character to the first).

Scanning the string in reverse order this way allows it to handle special cases. For example, numbers in the teens use two characters for one word. And a number such as 1000, uses one word for all three zeros.

Each time through the loop, the code determines the current column number. From that, it can determine if it is looking at a digit in the ones, tens, or hundreds postion. (After each thousands grouping, it starts again with the ones column.) It uses this information to determine exactly what must be done with the current digit.

Listing 1: The NumberToText Class

namespace NumToText
{
    static class NumberToText
    {
        private static string[] _ones =
        {
            "zero",
            "one",
            "two",
            "three",
            "four",
            "five",
            "six",
            "seven",
            "eight",
            "nine"
        };

        private static string[] _teens =
        {
            "ten",
            "eleven",
            "twelve",
            "thirteen",
            "fourteen",
            "fifteen",
            "sixteen",
            "seventeen",
            "eighteen",
            "nineteen"
        };

        private static string[] _tens =
        {
            "",
            "ten",
            "twenty",
            "thirty",
            "forty",
            "fifty",
            "sixty",
            "seventy",
            "eighty",
            "ninety"
        };

        // US Nnumbering:
        private static string[] _thousands =
        {
            "",
            "thousand",
            "million",
            "billion",
            "trillion",
            "quadrillion"
        };

        /// <summary>
        /// Converts a numeric value to words suitable for the portion of
        /// a check that writes out the amount.
        /// </summary>
        /// <param name="value">Value to be converted</param>
        /// <returns></returns>
        public static string Convert(decimal value)
        {
            string digits, temp;
            bool showThousands = false;
            bool allZeros = true;

            // Use StringBuilder to build result
            StringBuilder builder = new StringBuilder();
            // Convert integer portion of value to string
            digits = ((long)value).ToString();
            // Traverse characters in reverse order
            for (int i = digits.Length - 1; i >= 0; i--)
            {
                int ndigit = (int)(digits[i] - '0');
                int column = (digits.Length - (i + 1));

                // Determine if ones, tens, or hundreds column
                switch (column % 3)
                {
                    case 0:        // Ones position
                        showThousands = true;
                        if (i == 0)
                        {
                            // First digit in number (last in loop)
                            temp = String.Format("{0} ", _ones[ndigit]);
                        }
                        else if (digits[i - 1] == '1')
                        {
                            // This digit is part of "teen" value
                            temp = String.Format("{0} ", _teens[ndigit]);
                            // Skip tens position
                            i--;
                        }
                        else if (ndigit != 0)
                        {
                            // Any non-zero digit
                            temp = String.Format("{0} ", _ones[ndigit]);
                        }
                        else
                        {
                            // This digit is zero. If digit in tens and hundreds
                            // column are also zero, don't show "thousands"
                            temp = String.Empty;
                            // Test for non-zero digit in this grouping
                            if (digits[i - 1] != '0' || (i > 1 && digits[i - 2] != '0'))
                                showThousands = true;
                            else
                                showThousands = false;
                        }

                        // Show "thousands" if non-zero in grouping
                        if (showThousands)
                        {
                            if (column > 0)
                            {
                                temp = String.Format("{0}{1}{2}",
                                    temp,
                                    _thousands[column / 3],
                                    allZeros ? " " : ", ");
                            }
                            // Indicate non-zero digit encountered
                            allZeros = false;
                        }
                        builder.Insert(0, temp);
                        break;

                    case 1:        // Tens column
                        if (ndigit > 0)
                        {
                            temp = String.Format("{0}{1}",
                                _tens[ndigit],
                                (digits[i + 1] != '0') ? "-" : " ");
                            builder.Insert(0, temp);
                        }
                        break;

                    case 2:        // Hundreds column
                        if (ndigit > 0)
                        {
                            temp = String.Format("{0} hundred ", _ones[ndigit]);
                            builder.Insert(0, temp);
                        }
                        break;
                }
            }

            // Append fractional portion/cents
            builder.AppendFormat("and {0:00}/100", (value - (long)value) * 100);

            // Capitalize first letter
            return String.Format("{0}{1}",
                Char.ToUpper(builder[0]),
                builder.ToString(1, builder.Length - 1));
        }
    }
}

Using the Code

Using the code is easy. Convert is a static method so you don't need to create an instance of the class. Just call the Convert method with the value to be converted.

Listing 2: Calling the Convert Method

string result = NumberToText.Convert(12345.67);

Conclusion

I thought this code was kind of interesting. It's a very simple task. Yet, the code ended up getting a little convoluted. It's not a very natural task for a computer to do. But, if needed, it's a handy little routine.

End-User License

Use of this article and any related source code or other files is governed by the terms and conditions of The Code Project Open License.

Author Information

Jonathan Wood

I'm a software/website developer working out of the greater Salt Lake City area in Utah. I've developed many websites including Black Belt Coder, Insider Articles, and others.