Creating user-defined Excel functions (UDFs) – Part 2. Improved VBA code to spell a number in a text form.

In the previous post, we created Excel UDF, which translates a number into a text form, using Dollar/Cents as default currency type. We strictly relied on VBA code snippet, published on Microsoft’s knowledge base. While working with this code, we now realize that several enhancements to this UDF would be desirable.
First of all, when dealing with even amounts, we really don’t see a point of quite redundant“No Cents” message. Secondly, it appears that this code simply formats the amount specified, instead of rounding it. As an example $ 1,256.8789 will be spelled out as One Thousand Two Hundred Fifty Six Dollars and Eighty Seven Cents, but it really should be: One Thousand Two Hundred Fifty Six Dollars and Eighty Eight Cents. Next, we probably want to change our function name to reflect the fact it only translates dollar amounts, not any other currencies, nor non-currency amounts. This is definitely a matter of personal taste, but let’s call this function SpellNumberDollar and while at it, let’s change it’s input variable from MyNumber to Amount. Let’s then create a new universal UDF (SpellNumberCurrency), which could accept any currency type, instead of limiting ourselves to dollars. After all, we don’t have anything against Euros, do we? Finally, let’s write a true SpellNumber function, to spell out a non-currency number up to the third decimal point (thousandths), instead of current precision of two decimal points (hundredths.)
Let’s start with renaming our function and changing it’s parameter name:
Function SpellNumber(ByVal MyNumber)
needs to be changed to:
Function SpellNumberDollar(ByVal Amount)
Within our module, we now need to replace one occurrence of SpellNumber with SpellNumberDollar and multiple occurrences of MyNumber with Amount.
To rid off the “No Cents” message, we simply need to replace one line of code
Cents = " and No Cents"
with the folllowing:
Cents = ""
Now, we can use ROUND function to properly display the cents portion of our amount:
Amount = Trim(Str(Amount))
becomes:
Amount = Round(Trim(Str(Amount)), 2)
To test all changes made, we now should be able to see function results as illustrated below:
Should your results differ, you can check your code to ensure that it conforms with desired code:
'Original function created by Microsoft,
'renamed to better describe it's purpose:
'Spell out any currency amounts in dollars and cents
Function SpellNumberDollar(ByVal Amount)
Dim Dollars, Cents, Temp
Dim DecimalPlace, Count
ReDim Place(9) As String
Place(2) = " Thousand "
Place(3) = " Million "
Place(4) = " Billion "
Place(5) = " Trillion "
' String representation of the amount
' Small change to round the amount of currency used to 2 decimals
' By Excel Strategies, LLC
Amount = Round(Trim(Str(Amount)), 2)
' Position of decimal place, 0 if none
DecimalPlace = InStr(Amount, ".")
' Convert cents and set Amount to dollar amount
If DecimalPlace > 0 Then
Cents = GetTens(Left(Mid(Amount, DecimalPlace + 1) & _
"00", 2))
Amount = Trim(Left(Amount, DecimalPlace - 1))
End If
Count = 1
Do While Amount <> ""
Temp = GetHundreds(Right(Amount, 3))
If Temp <> "" Then Dollars = Temp & Place(Count) & Dollars
If Len(Amount) > 3 Then
Amount = Left(Amount, Len(Amount) - 3)
Else
Amount = ""
End If
Count = Count + 1
Loop
Select Case Dollars
Case ""
Dollars = "No Dollars"
Case "One"
Dollars = "One Dollar"
Case Else
Dollars = Dollars & " Dollars"
End Select
Select Case Cents
Case ""
Cents = ""
Case "One"
Cents = " and One Cent"
Case Else
Cents = " and " & Cents & " Cents"
End Select
SpellNumberDollar = Dollars & Cents
End Function
Notice, that if you happen to be proficient with built-in Excel functions, Excel makes it very simple to use their VBA equivalents. Since we are only beginning our VBA travels, let’s not worry about typical rookie mistakes: implicit declaration of variables, reusing variables, absence of any error handling routines, and so forth.
To create universal currency function, we now want to replace this code line
Function SpellNumberDollar(ByVal Amount)
with the one asking for additional currency parameters:
SpellNumberCurrency(ByVal Amount, strDollars, strCents)
To perform actual currency string manipulation, below code excerpt
Select Case Dollars
Case ""
Dollars = "No Dollars"
Case "One"
Dollars = "One Dollar"
Case Else
Dollars = Dollars & " Dollars"
End Select
Select Case Cents
Case ""
Cents = ""
Case "One"
Cents = " and One Cent"
Case Else
Cents = " and " & Cents & " Cents"
End Select
should be changed to:
Select Case Dollars
Case ""
Dollars = ""
Case "One"
Dollars = "One " & Left(strDollars, Len(strDollars) - 1)
Case Else
Dollars = Dollars & " " & strDollars
End Select
Select Case Cents
Case ""
Cents = ""
Case "One"
Cents = " and One " & Left(strCents, Len(strCents) - 1)
Case Else
Cents = " and " & Cents & " " & strCents
End Select
Once again, this code should be rather self-explanatory for anyone who has done text manipulation via built-in Excel functions (LEFT, LEN, &…) Basically, we are passing currency parameters (strDollars and strCents) instead of hard-coding “Dollars” and “Cents” as in previous example. Additionally, to ensure proper singular form spelling, we are eliminating last letter in both parameters (typically letter ‘s’.)
Let’s test this function to convert numbers denominated in different world currencies:
The last UDF we will create today is true SpellNumber function. Our goal is to spell out a non-currency amount with a precision set up to the third decimal point (thousandths.) :
We will use below VBA code to generate this UDF:
'Modified version of Microsoft function
'By Excel Strategies, LLC
'This function spells out any number with a precision of up
'to 3 decimal places (enhancement over 2 decimal places)
Public Function SpellNumber(ByVal Amount)
'Define variables
Dim Numbers, Numbers2, Decimals, Decimals2, Temp, Temp2
Dim DecimalPlace, Count
ReDim Place(9) As String
Place(2) = " Thousand "
Place(3) = " Million "
Place(4) = " Billion "
Place(5) = " Trillion "
'String representation of amount, that also rounds it
'up to 3 decimal places
Amount = Round(Trim(Str(Amount)), 3)
'Position of decimal place: 0 if none.
DecimalPlace = InStr(Amount, ".")
' Convert decimals and set Amount to whole amount.
If DecimalPlace > 0 Then
'All numbers after period, if any
Decimals = Right(Amount, Len(Amount) - DecimalPlace)
'Precision level of the number (0-3)
Decimals2 = Len(Decimals)
'Whole number (digits to the left of perido)
Amount = Trim(Left(Amount, DecimalPlace - 1))
'Spell out hundreds/tens in the decimal portion
Do While Decimals <> ""
Temp2 = GetHundreds(Right(Decimals, 3))
If Temp2 <> "" Then Numbers2 = Temp2 & Place(Count) & Numbers2
If Len(Decimals) > 3 Then
Decimals = Left(Decimals, Len(Decimals) - 3)
Else
Decimals = ""
End If
Count = Count + 1
Loop
End If
Count = 1
'Spell out hundreds/tens in the amount
Do While Amount <> ""
Temp = GetHundreds(Right(Amount, 3))
If Temp <> "" Then Numbers = Temp & Place(Count) & Numbers
If Len(Amount) > 3 Then
Amount = Left(Amount, Len(Amount) - 3)
Else
Amount = ""
End If
Count = Count + 1
Loop
'Construct number/whole portion
Select Case Numbers
Case ""
Numbers = "Not a number"
Case "One"
Numbers = "One"
Case Else
Numbers = Numbers
End Select
'Construct decimal portion
Select Case Numbers2
Case ""
Numbers2 = ""
Case 0
Numbers2 = ""
Case Else
Numbers2 = " and " & Numbers2
End Select
'Add appropriate suffix to the decimal portion
Select Case Decimals2
Case 0
Decimals = ""
Case 1
Decimals = " Tenths"
Case 2
Decimals = " Hundredths"
Case Is > 2
Decimals = " Thousandths"
Case Else
Decimals = ""
End Select
'Concatenate all variables into one master answer
SpellNumber = Numbers & Numbers2 & Decimals
End Function
For your convenience, you can download revised Excel file and start using all three functions right away.