B4J Question Number to text N2T ?

Beja

Expert
Licensed User
Longtime User
Hello all,
Anyone has an Idea?
I want to convert a money amount e.g. $250.50 to a a text string like the one we all do when writing a check to someone.
$250.50 "Two hundred and fifty Dollars and fifty cents"

Thanks in advance
 

emexes

Expert
Licensed User
Anyone has an Idea?
I want to convert a money amount e.g. $250.50 to a a text string like the one we all do when writing a check to someone.
$250.50 "Two hundred and fifty Dollars and fifty cents"

Righto, here's my first draft. Slightly overboard per usual. In retrospect, should have put the formatting stuff into a compound variable rather than as a bunch of parameters, but I'll leave that project for a rainy day. Also, I used Long rather than Double, thinking precision might be a problem for large numbers, but... if a Double can hold the US national debt down to the last penny, then it's good enough for writing checks.

Add these functions:

B4X:
Sub DollarsToWords(M As Double) As String

    Return CentsToWords(M * 100)

End Sub

Sub CentsToWords(N As Long) As String

    If N < 0 Then
        Log("!!! WTF ??? " & N & " !!!")
        '''Dim SomePeopleGottaLearnTheHardWay As String = "".SubString(-1)
        Return("Nothing : All Sales Are Final")    'Plan B
    End If

    Return( MoneyToWords( _
        N, _
        Array As String("Dollar", "Dollars"), _    'or "Euro" or "Franc"
        Array As String("Cent", "Cents"), _
        100, _    'I have a vague recollection of a currency that divides by 1000
        "Zilch", _    'or "" or "No"
        "Exactly", _    'or "" or " "
        ", " _    'or "" or " And " or " & " or "&"
    ))
 
End Sub

Sub MoneyToWords(N As Long, BigNameSinglePlural() As String, LittleNameSinglePlural() As String, NumLittleInBig As Int, ZeroWord As String, ZeroLittleWord As String, JoinBigLittleWord As String) As String
 
    If N = 0 Then
        Return("Absolutely Nothing")
    End If
 
    Dim NumBig As Long = N / NumLittleInBig
    Dim NumLittle As Int = N - NumBig * NumLittleInBig
 
    Dim sb As StringBuilder
    sb.Initialize

    If NumBig = 0 And ZeroWord.Length <> 0 Then
        sb.Append(ZeroWord)
    Else
        sb.Append(NumberToWords(NumBig))
    End If
    sb.Append(" ")
    If NumBig = 1 Then
        sb.Append(BigNameSinglePlural(0))
    Else
        sb.Append(BigNameSinglePlural(1))
    End If

    If NumLittle = 0 And ZeroLittleWord.Length <> 0 Then
        sb.Append(" ")
        sb.Append(ZeroLittleWord)    'eg "xxx Dollars Exactly" rather than "xxx Dollars And Zero Cents"
    Else
        If JoinBigLittleWord.Length <> 0 Then
            sb.Append(JoinBigLittleWord)
        Else
            sb.Append(" & ")
        End If
  
        If NumLittle = 0 And ZeroWord.Length <> 0 Then
            sb.Append(ZeroWord)
        Else
            sb.Append(NumberToWords(NumLittle))
        End If
        sb.Append(" ")
        If NumLittle = 1 Then
            sb.Append(LittleNameSinglePlural(0))
        Else
            sb.Append(LittleNameSinglePlural(1))
        End If
    End If

    Return sb.ToString
  
End Sub

Sub NumberToWords(N As Long) As String
 
    If N < 0 Then
        Return "Minus " & NumberToWordsPositive(-N)
    Else
        Return NumberToWordsPositive(N)    'including zero
    End If
 
End Sub

Sub NumberToWordsPositive(N As Long) As String
 
    If N = 0 Then
        Return "Zero"    'that gets rid of that pesky special case
    End If
 
    Dim GroupsOfThree(10) As Int
 
    Dim NumGroupsOfThree As Int = 0
 
    Do While N <> 0
        GroupsOfThree(NumGroupsOfThree) = N Mod 1000
        NumGroupsOfThree = NumGroupsOfThree + 1
 
        N = N / 1000
    Loop
 
    Dim Temp As String = ""
    For GroupOfThree = NumGroupsOfThree - 1 To 0 Step -1
        Dim ThisGroup As Int = GroupsOfThree(GroupOfThree)
 
        If ThisGroup <> 0 Then
            If Temp.Length <> 0 Then
                If GroupOfThree = 0 And ThisGroup < 100 Then
                    Temp = Temp & " and "
                Else
                    Temp = Temp & ", "
                End If
            End If
  
            Temp = Temp & NumberToWords1000(ThisGroup)
  
            If GroupOfThree <> 0 Then
                Temp = Temp & " " & ThousandWords(GroupOfThree)
            End If
        End If
    Next
 
    Return Temp

End Sub

Sub NumberToWords1000(N As Int) As String
 
    If N < 100 Then
        Return NumberToWords100(N)
    End If
 
    Dim Hundreds As String = UnitWords(N / 100) & " Hundred"    'Hundreds always non-blank since N < 100 already done
    Dim TensUnits As String = NumberToWords100(N Mod 100)    'TensUnits could be blank if digits are 00
 
    If TensUnits.Length = 0 Then
        Return Hundreds
    Else
        Return Hundreds & " and " & TensUnits
    End If
 
End Sub

Sub NumberToWords100(N As Int) As String
 
    If N < 20 Then
        Return UnitWords(N)
    End If
 
    Dim Tens As String = TenWords(N / 10)    'Tens always non-blank since N < 20 already done
    Dim Units As String = UnitWords(N Mod 10)    'Units could be blank if digit is 0
 
    If Units.Length = 0 Then
        Return Tens
    Else
        Return Tens & "-" & Units
    End If
 
End Sub
 
Last edited:
Upvote 0

emexes

Expert
Licensed User
and this test function:

B4X:
Sub TestDollarsToWords(M As Double) As String
    
    Return(M & " = Pay Beja " & DollarsToWords(M))
    
End Sub

and then try these test cases:

B4X:
Log(TestDollarsToWords(0))
Log(TestDollarsToWords(0.01))
Log(TestDollarsToWords(0.10))
Log(TestDollarsToWords(0.11))
Log(TestDollarsToWords(0.99))
Log(TestDollarsToWords(1.00))
Log(TestDollarsToWords(1.01))
Log(TestDollarsToWords(1.11))
Log(TestDollarsToWords(1.99))
Log(TestDollarsToWords(11.01))
Log(TestDollarsToWords(11.11))
Log(TestDollarsToWords(11.99))
Log(TestDollarsToWords(99.01))
Log(TestDollarsToWords(99.11))
Log(TestDollarsToWords(99.99))
Log(TestDollarsToWords(250.50))
Log(TestDollarsToWords(31132235607890.12))    'https://www.usdebtclock.org 10/10/2022
Log(TestDollarsToWords(-0.01))

and with luck you'll get something like:

Log output:
Waiting for debugger to connect...
Program started.
0 = Pay Beja Absolutely Nothing
0.01 = Pay Beja Zilch Dollars, One Cent
0.1 = Pay Beja Zilch Dollars, Ten Cents
0.11 = Pay Beja Zilch Dollars, Eleven Cents
0.99 = Pay Beja Zilch Dollars, Ninety-Nine Cents
1 = Pay Beja One Dollar Exactly
1.01 = Pay Beja One Dollar, One Cent
1.11 = Pay Beja One Dollar, Eleven Cents
1.99 = Pay Beja One Dollar, Ninety-Nine Cents
11.01 = Pay Beja Eleven Dollars, One Cent
11.11 = Pay Beja Eleven Dollars, Eleven Cents
11.99 = Pay Beja Eleven Dollars, Ninety-Nine Cents
99.01 = Pay Beja Ninety-Nine Dollars, One Cent
99.11 = Pay Beja Ninety-Nine Dollars, Eleven Cents
99.99 = Pay Beja Ninety-Nine Dollars, Ninety-Nine Cents
250.5 = Pay Beja Two Hundred and Fifty Dollars, Fifty Cents
3.113223560789012E13 = Pay Beja Thirty-One Trillion, One Hundred and Thirty-Two Billion, Two Hundred and Thirty-Five Million, Six Hundred and Seven Thousand, Eight Hundred and Ninety Dollars, Twelve Cents
!!! WTF ??? -1 !!!
-0.01 = Pay Beja Nothing : All Sales Are Final
 
Upvote 0

emexes

Expert
Licensed User
$250.50 "Two hundred and fifty Dollars and fifty cents"

I just realised I used ", " to separate dollar and cent amounts, instead of your " and ", but that's easy enough to change here:

B4X:
Return( MoneyToWords( _
    N, _
    Array As String("Dollar", "Dollars"), _    'or "Euro" or "Franc"
    Array As String("Cent", "Cents"), _
    100, _    'I have a vague recollection of a currency that divides by 1000
    "Zilch", _    'or "" or "No"
    "Exactly", _    'or "" or " "
    ", " _    'or "" or " And " or " & " or "&"
))

Also, I return the first letter of each word uppercase, so that you can then .ToUpperCase or .ToLowerCase if you prefer one of those styles better.

But your example has an uppercase D for Dollars but lowercase c for cents. How essential is that? If it is life and death, then you could:

B4X:
Dim FirstLettersUpperCase As String = "Two Hundred And Fifty Dollars And Fifty Cents"
Dim FirstLetterUpperCase As String = FirstLettersUpperCase.CharAt(0) + FirstLettersUpperCase.SubString(1)    'might crash if string is empty
Dim BejaCase As String = FirstLetterUpperCase.Replace(" dollars", " Dollars")
 
Last edited:
Upvote 0

Beja

Expert
Licensed User
Longtime User
Yet another enhancement idea. ?
aka: If we don't laugh, we'll cry.

B4X:
Sub DollarsToWords(M As Double) As String

    If M > 27e12 Then    'give or take a few hundred billion
        Return("Let's Go Brandon")   '= first three letters of LGBTQ... not quite sure what to read into that
    End If
  
    Return CentsToWords(M * 100)

End Sub

https://babylonbee.com/news/9-ways-for-congress-to-pay-off-the-31-trillion-national-debt

Thanks for the efforts
Not about give or take.. it's about converting a number representing currency to words. or N2W
 
Upvote 0
Top