Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Convert numbers to words in English and Asian format

0.00/5 (No votes)
3 Jan 2012 1  
Convert number to readable words

Introduction 

I was going through the articles and ran into an article that showed the conversion of number to words, such as 12 to Twelve.  I though let me try same thing but in a different way. I am not a programmer but like to monkey around with codes.

I have/will be adding other languages that I may NOT know. For example, Indonesian which I recently added can’t even pronounce the converted words; yet made the converter. Point is, please verify and let me know if any improvements are needed. Thanks.

Anyways, the Converter class allows us to convert the numbers into words. Let the picture talk!

 IntroImage.png

Background 

Before digging into the code let’s see how the numbers are read in word

In English Style (US): 

123,123,000 =  One hundred twenty three million one hundred twenty three thousand
123,000,000 =  One hundred twenty three million
      123,000 =                                                 One hundred twenty three thousand
english_us_and_uk_image.png 

As we can see the three set of numbers are always spelled same way and then the modifier, like million is appended. In English style numbers are aggregated in a group of three. In Asian style it’s little bit different. The last (towards right) three are grouped together and then rests of the numbers are aggregated with two words.

In South Asian Style: 

12,12,112 = Twelve lakh twelve thousand one hundred twelve
12,00,000 = Twelve lakh
      12,000 =                        twelve thousand
            112 =                                                          one hundred twelve
South_Asian_style_numbers_to_words.png

In Indonesian Style: 

123,123,100 = Seratus Dua Puluh Tiga Juta Seratus Dua Puluh Tiga Ribu
123,000,000 = Seratus Dua Puluh Tiga Juta
        123,000 =                                                    Seratus Dua Puluh Tiga Ribu
indonesian_style_numbers_to_words.png

Code  Flow 

The absolute common thing between these two systems is the digit. 1 is one, 9 is nine and 20 is twenty in both.  And the difference is how the higher numbers are grouped and read. To facilitate these I created arrays. These arrays are the heart of the conversion. The tricky part is to find the index so that we can use these arrays.

Private SingleDigitStringArray() As String = _
        {"", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten"}
Private DoubleDigitsStringArray() As String = _
        {"", "Ten", "Twenty", "Thirty", "Forty", "Fifty", "Sixty", "Seventy", "Eighty", "Ninety"}
Private TenthDigitStringArray() As String = _
        {"Ten", "Eleven", "Tweleve", "Thirteen", "Fourteen", "Fifteen", "Sixteen", "Seventeen", _
         "Eighteen", "Nineteen"}

Private HigherDigitEnglishStringArray() As String = _
        {"", "", "Hundred", "Thousand", "Million", "Billion", "Trillion", "Quadrillion", "Quintillion"}
Private HigherDigitAsianStringArray() As String = _
        {"", "", "Hundred", "Thousand", "Lakh", "Karod", "Arab", "Kharab"}

Private EnglishCodeArray() As String = {"1", "22", "3"}
Private AsianCodeArray() As String = {"1", "22", "3", "4", "42", "5", "52", "6", "62", "7", "72", "8", "82"} 

Private IndonesianCodeArray() As String = {"1", "22", "3", "4", "42", "420"}
Private SingleDigitIndonesianArray() As String = {"", "Satu", "Dua", "Tiga", "Empat", "Lima", "Enam", _
                                                  "Tujuh", "Delapan", "Sembilan"}
Private DoubleDigitIndonesianArray() As String = {"Puluh", "Belas"}
Private HigherDigitIndonesianStringArray() As String = {"", "", "Ratus", "Ribu", "Juta", "Miliar", "Triliun"}

The entire process is basically array manipulation. The primary goal is to find the correct index corresponding to the number and its position and then pulling the corresponding word out of the array shown above.

Let’s get the ball rolling.  In English conversion method, we work 3 digits at a time from right side and then affix the thousand/million as necessary and loop until we are done, as shown below:

Do
	concatHigherDigitString = False
	If i > 3 Then concatHigherDigitString = True 'to suffix the Thousand/Million/Billion type of Word


	If newAmount.Length >= 4 Then   'work with 3 right most digits at a time
		newAmount = amountString.Substring(amountString.Length - i, 3)
	End If


	'do the conversion and affix the Thousand/Million/Billion type of word at the end when needed
	If concatHigherDigitString AndAlso CInt(newAmount) <> 0 Then
		result = ThreeDigitsConverter(CInt(newAmount)) & " " & _
                          HigherDigitEnglishStringArray(i / 3 + 1) & " " & result
	Else
		result = ThreeDigitsConverter(CInt(newAmount))
	End If


	workedStringLength += newAmount.Length
	newAmount = amountString.Substring(0, amountString.Length - workedStringLength)
	i += 3
Loop Until amountString.Length <= workedStringLength


In both of the method, we first convert the given number to string and then to an array, for instance, 1234 to “1234” and then to {1, 2, 3, 4}, using following simple code. I believe there must be a better way of doing this…

'convert numbers to array of each digit
Dim amountArray(amountString.Length - 1) As Integer
For i As Integer = amountArray.Length To 1 Step -1
   amountArray(i - 1) = amountString.Substring(i - 1, 1)
Next

Now we work on digit by digit but backwards as the digit in unit place remains in unit place all the time.  Things get little complicated when working with numbers like 12 because it’s not read like onetwo however as Twelve. Similarly, 22 is not twotwo but Twenty two. Likewise, 10001 is not Ten thousand zero hundred one but it’s Ten thousand one. Keeping all these in minds, following loop will find the right index and then from the words library (fields array that we talked about earlier) we convert the digits to word.

Primary method for number to English word conversion

Converting to English method is kind of straight forward compared to other methods. There aren't that many unique situation so it's not that difficult to find the correct index of required array.

    For i As Integer = amountArray.Length To 1 Step -1
      j = amountArray.Length - i
      digit = amountArray(j)

      codeIndex = EnglishCodeArray(i - 1)
      higherDigitEnglishString = HigherDigitEnglishStringArray(CInt(codeIndex.Substring(0, 1)) - 1)


      If codeIndex = "1" Then 'Number [1 9]
        result = result & SingleDigitStringArray(digit)

      ElseIf codeIndex.Length = 2 And digit <> 0 Then 'Number in tenth place and skip if digit is 0

        If digit = 1 Then   'Number [Eleven, Twelve,...., Nineteen]
          Dim suffixDigit As Integer = amountArray(j + 1)
          result = result & separator & TenthDigitStringArray(suffixDigit) & " " & higherDigitEnglishString
          i -= 1  'Skip the next round as we already looked at it

        Else    'Number [tenth] and [20+] 

          If Me.Style = ConvertStyle.EnglishUK Then
            result = result & separator & DoubleDigitsStringArray(digit) & "-" & higherDigitEnglishString
          ElseIf Me.Style = ConvertStyle.EnglishUS Then
            result = result & separator & DoubleDigitsStringArray(digit) & " " & higherDigitEnglishString
          End If

        End If

      ElseIf digit <> 0 Then  'Standard Number like 100, 1000, 1000000 and skip if digit is 0

        If Me.Style = ConvertStyle.EnglishUK Then andSeparator = " and"
        result = result & separator & SingleDigitStringArray(digit) & " " & higherDigitEnglishString _ 
                                                                          & andSeparator

      End If

      separator = " "
    Next

Primary method for number to Indonesian word conversion

Indonesian style is somewhat similar to English style but there are several unique cases which makes it difficult. The challenging part for was a number when starts with "1".  When a numbers starts with 1, the two words merge to one but it's not just the simple concatenation. The funny part is I can't even pronounce the converted word correctly!

For i As Integer = amountArray.Length To 1 Step -1
      j = amountArray.Length - i
      digit = amountArray(j)

      codeIndex = IndonesianCodeArray(i - 1)
      higherDigitIndonesianString = HigherDigitIndonesianStringArray(CInt(codeIndex.Substring(0, 1)) - 1)


      If codeIndex = "1" Then 'Number [1, 9]
        result = result & separator & SingleDigitIndonesianArray(digit)

      ElseIf codeIndex.Length = 2 And digit <> 0 Then 'Number in tenth place and skip if digit is 0
        Dim suffixDigit As Integer = amountArray(j + 1)

        If digit = 1 And suffixDigit < 2 Then   'Number [Ten and Eleven] 'Sepuluh, Sebelas
          result = result & separator & "Se" & DoubleDigitIndonesianArray(suffixDigit).ToLower & " " & _
                                               higherDigitIndonesianString
          i -= 1

        ElseIf digit = 1 And suffixDigit >= 2 Then    'Number [12, 19]  
          result = result & separator & SingleDigitIndonesianArray(suffixDigit) & " " & _
                                        DoubleDigitIndonesianArray(1) & " " & higherDigitIndonesianString
          i -= 1

        ElseIf suffixDigit <> 0 Then 'Numbers like [21, 22,..29,31,32..39,41....99] ' except ?0s, ??0s
          result = result & separator & SingleDigitIndonesianArray(digit) & " " & _
                                        DoubleDigitIndonesianArray(0)

        Else 'Numbers like [20 30 40...90]
          result = result & separator & SingleDigitIndonesianArray(digit) & " " & _
                                        DoubleDigitIndonesianArray(0) & " " & higherDigitIndonesianString

        End If

      ElseIf digit <> 0 Then  'Standard Number like 100+, 1000+, 1000000+ and skip if digit is 0
        If digit = 1 Then   'exactly numbers like 100, 1000, 1000000
          result = result & separator & "Se" & higherDigitIndonesianString.ToLower
        Else
          result = result & separator & SingleDigitIndonesianArray(digit) & " " & higherDigitIndonesianString
        End If

      End If

      separator = " "
    Next


During the process a space or two get attached in between the words so for the cleanup I use the RegEx as:

Private Function RemoveSpaces(ByVal word As String) As String
  Dim regEx As New System.Text.RegularExpressions.Regex("  ")
  Return regEx.Replace(word, " ").Trim
End Function 

There we go, this will convert the numbers to digits!

Number formatting (or grouping):

There is another public function FormatNumber which basically calls a private FormatNumberPerLanguage in the Converter class. This FormatNumberPerLanguage will format group based on the provided regional name. A simple use of CultureInfo class.

Private Function FormatNumberPerLanguage(ByVal culterInfoName As String)
    Dim ci As New System.Globalization.CultureInfo(culterInfoName)
    ci.NumberFormat.NumberDecimalDigits = 0
    Return Me.Amount.ToString("N", ci)
End Function 

Using the code 

Simply create a new instance of the converter and pass the number you want to convert and the conversion style and call the Convert method.

Blocks of code should be set as style "Formatted" like this:  

Dim converter As New Converter(number, converter.ConvertStyle.EnglishUS)
Me.RichTextBox1.Text = converter.Convert

converter = New Converter(number, NumberToWords.Converter.ConvertStyle.Asian)
Me.RichTextBox2.Text = converter.Convert   

Points of Interest

These two arrays are worth mentioning

Private EnglishCodeArray() As String = {"1", "22", "3"}
Private AsianCodeArray() As String = {"1", "22", "3", "4", "42", "5", "52", "6", "62", "7", "72", "8", "82"}
Private IndonesianCodeArray() As String = {"1", "22", "3", "4", "42", "420"}

…these two arrays help to determine whether a digit is in unit place or, tenth place and so on… In the above array, double digit like “22” will always represent the 10th place. “4” will represent thousand and “42” will represent ten thousand.

Somewhere I have a feeling I have not done enough testing so comments are actually what I am expecting. Thanks! 

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here