Page 1 of 1

Convert Numerical Currency Into Words

Posted: 04 Feb 2023, 12:54
by AlFlo
I frequently have to convert numerical dollar figures like $1,876,543.21 into words, i.e.:

One Million Eight Hundred and Seventy-Six Thousand Five Hundred and Forty-Three Dollars and Twenty-One Cents

And vice-versa.

I've gotten pretty close tinkiering with the following AHK script originally based on a script written by jeeswg (although it writes "and Two One Cents" instead of "and Twenty-One Cents"). But how do I write a script going the OTHER way ... where it converts words into numbers? I.e. how do I place "One Million Eight Hundred and Seventy-Six Thousand Five Hundred and Forty-Three Dollars and Twenty-One Cents" in clipboard and have it spit out "$1,876,543.21"?

Code: Select all

vNum := Clipboard ; I START BY PLACING THE NUMBERS IN CLIPBOARD

tempVar := % JEE_NumToWord(vNum)
 
q:: Send %tempVar%  ; WHEN I PRESS "Q", IT PASTES THE WORD VERSION OF THE NUMBERS
return

;==================================================

;JEE_NumSpell
;JEE_SpellNum
JEE_NumToWord(vNum, vDoTrimFrac:=1, vAddExtraAnd:=0)
{
	if !vNum
		return "zero"

	oArrayX := StrSplit("Thousand,Million,Billion,Trillion,Quadrillion,Quintillion,Sextillion,Septillion,Octillion,Nonillion,Decillion", ",")
	(oArrayU := StrSplit("Zero,One,Two,Three,Four,Five,Six,Seven,Eight,Nine,Ten,Eleven,Twelve,Thirteen,Fourteen,Fifteen,Sixteen,Seventeen,Eighteen,Nineteen", ",")).RemoveAt(0)
	oArrayT := StrSplit("Ten,Twenty,Thirty,Forty,Fifty,Sixty,Seventy,Eighty,Ninety", ",")

	vNum := StrReplace(vNum, "-", "", vCount)
	if vCount
		vOutput := "minus "
	vNum := StrReplace(vNum, ",")
	vNum1 := LTrim(StrSplit(vNum, ".")[1], "0")
	if vDoTrimFrac
		vNum2 := RTrim(StrSplit(vNum, ".")[2], "0")
	else
		vNum2 := StrSplit(vNum, ".")[2]

	if ((vLen := StrLen(vNum1)) > 36)
		return
	if (Mod(vLen, 3) = 1)
		vNum1 := "00" vNum1
	else if (Mod(vLen, 3) = 2)
		vNum1 := "0" vNum1

	vMag := Ceil(vLen/3)-1
	Loop, % Ceil(vLen/3)
	{
		oTemp := StrSplit(SubStr(vNum1, (A_Index*3)-2, 3))
		vTemp := (oTemp.2 * 10) + oTemp.3
		if oTemp.1
			vOutput .= oArrayU[oTemp.1] " Hundred" (vTemp?" and ":" ")
		else if !vMag && (vLen > 3) && vAddExtraAnd
			vOutput .= "and "

		if (vTemp >= 20)
			vOutput .= oArrayT[oTemp.2] (oTemp.3?"-" oArrayU[oTemp.3]:" ")
		else if vTemp
			vOutput .= oArrayU[vTemp]
		vOutput .= " " oArrayX[vMag] " "
		vMag--
	}
vOutput .= "Dollars "
	vOutput := RTrim(vOutput, " ")
	if !vNum2
		return vOutput
	if (vOutput = "")
		vOutput := "zero"
	vOutput .= " and"
	Loop, Parse, vNum2
		; vOutput .= "-" oArrayU[A_LoopField]
	vOutput .= " " oArrayU[A_LoopField]
vOutput .= " Cents "
	return RTrim(vOutput)
}

;==================================================

Re: Convert Numerical Currency Into Words

Posted: 04 Feb 2023, 15:41
by Chunjee
challenging










very challenging

Re: Convert Numerical Currency Into Words

Posted: 04 Feb 2023, 19:53
by AlFlo
You know, the funny thing is I found something better than my script to convert numbers into words, a website: https://www.calculatorsoup.com/calculators/conversions/numberstowords.php . I wrote a little AHK script to take the number in my clipboard, paste it into that webpages input box, and convert it into words on that website using the correct formatting (title case, currency).

I might be able to find something similar for converting words into numbers.

If not, I might try brute forcing it through Regex, i.e.:

replace "One" every time it appears with "1"
replace "Two" every time it appears with "2"
etc.

The hard parts would probably be:

(1) distinguishing between the words "Twenty Seven" meaning "27" versus "20 7" ... although, for my purposes, I think it would always mean "27"; and

(2) Replacing the last two words with a decimal point and number of cents if the word "cents" appears.

Re: Convert Numerical Currency Into Words

Posted: 04 Feb 2023, 20:43
by AlFlo
Yeah, this website converts words into numbers: https://www.dcode.fr/writing-words-numbers

It would be nice to have an AHK script to be able to convert words and numbers back and forth ...

But - given the existence of websites like these - it's not a necessity.

Re: Convert Numerical Currency Into Words

Posted: 04 Feb 2023, 21:46
by mikeyww
viewtopic.php?p=422642#p422642 (would need to revise for large numbers)

Just proof of concept, may need debugging:

Code: Select all

; This script converts words to a number
#Requires AutoHotkey v2.0
MsgBox wordsToNum("One Million Eight Hundred and Seventy-Six Thousand Five Hundred and Forty-Three")

wordsToNum(str) {
 Static tens     := Map('ten'  , 10, 'twenty' , 20, 'thirty', 30, 'forty' , 40, 'fifty', 50
                      , 'sixty', 60, 'seventy', 70, 'eighty', 80, 'ninety', 90)
      , ones     := Map('one', 1, 'two'  , 2, 'three', 3, 'four', 4, 'five', 5
                      , 'six', 6, 'seven', 7, 'eight', 8, 'nine', 9)
      , place    := Map('million', 1000000, 'thousand', 1000, 'hundred', 100)
      , tensStr  := "", onesStr := ""
 If !tensStr
  For word in tens
   tensStr .= (tensStr = "" ? "" : "|") word
 If !onesStr
  For word in ones
   onesStr .= (onesStr = "" ? "" : "|") word
 str := StrReplace(Format("{:L}", str), " and ", " ")
 For each, pl in ['million', 'thousand', 'hundred'] {
  RegExMatch(str, 'i)((.+)\h+' pl ')?(\h*(.*))?', &m)
  If m[2]
   Return (wordsToNum(m[2]) * place[pl] || 0) + (wordsToNum(m[4]) || 0)
 }
 RegExMatch(m[4], 'i)(' tensStr ')?[- ]?(' onesStr ')?', &m)
 Return (tens.Has(m[1]) ? tens[m[1]] : 0) + (ones.Has(m[2]) ? ones[m[2]] : 0)
}
image230204-2145-001.png
Output
image230204-2145-001.png (3.38 KiB) Viewed 1316 times

Re: Convert Numerical Currency Into Words

Posted: 04 Feb 2023, 22:15
by gmoises
Corrected a bug in the get cents part

Added Format option:
If Format is "$" or If The first character in Num is "$"
the return includes "Dollars"

Num can include commas (,)

Code: Select all

N := "$123456789.045"
MsgBox % SpellNumber(N)
ExitApp

SpellNumber(Num, Format := "") {
	Place := [" ", " Thousand ", " Million ", " Billion ", " Trillion "]
	Num := Trim(StrReplace(Num, ",", ""))
	If SubStr(Num, 1, 1) = "$" or InStr(Format, "$")
		Dls := "Dollars ", Num := StrReplace(Num, "$", "")
	
	; get cents
	If DecimalPoint := InStr(Num, ".")
	{	Cen := Tens(SubStr(SubStr(Num, DecimalPoint + 1) . "00", 1, 2))
		Num := SubStr(Num, 1, DecimalPoint - 1)
	}

	Cnt := 1
	While Num != ""
	{	h := Hundreds(SubStr(Num, -2))
		If h
			Dollars := h . Place[Cnt] . Dollars
		Num := StrLen(Num) > 3 ? SubStr(Num, 1, -3) : ""
		++Cnt
	}
	
	Switch Cen
	{	Case "":
			Cents := Dls . " and No Cents"
		Case "One":
			Cents := Dls . " and One Cent"
		Default:
			Cents := Dls . " and " . Cen . " Cents"
	}
	Return, StrReplace(Dollars . Cents, "  ", " ")
}

; get hundreds
Hundreds(Num) {
	If (Num = 0)
		Return, ""
	Num := SubStr("000" . Num, -2)
	If SubStr(Num, 1, 1) != "0"
		Ret := Digits(SubStr(Num, 1, 1)) . " Hundred "
	If SubStr(Num, 2, 1) != "0"
		Return, Ret . Tens(SubStr(Num, 2))
	Else
		Return, Ret . Digits(SubStr(Num, 3))
}

; get tens
Tens(Num) {
	If (Num > 9 and Num < 20)
		Switch Num
		{	Case 10: Return, "Ten"
			Case 11: Return, "Eleven"
			Case 12: Return, "Twelve"
			Case 13: Return, "Thirteen"
			Case 14: Return, "Fourteen"
			Case 15: Return, "Fifteen"
			Case 16: Return, "Sixteen"
			Case 17: Return, "Seventeen"
			Case 18: Return, "Eighteen"
			Case 19: Return, "Nineteen"
		}
	Else
		Switch SubStr(Num, 1, 1)
		{	Case 2: Ret := "Twenty "
			Case 3: Ret := "Thirty "
			Case 4: Ret := "Forty "
			Case 5: Ret := "Fifty "
			Case 6: Ret := "Sixty "
			Case 7: Ret := "Seventy "
			Case 8: Ret := "Eighty "
			Case 9: Ret := "Ninety "
		}
	Return, Ret . Digits(SubStr(Num, 2, 1))
}

Digits(Num) {
	Switch Num
	{	Case 1: Return, "One"
		Case 2: Return, "Two"
		Case 3: Return, "Three"
		Case 4: Return, "Four"
		Case 5: Return, "Five"
		Case 6: Return, "Six"
		Case 7: Return, "Seven"
		Case 8: Return, "Eight"
		Case 9: Return, "Nine"
		Default: Return, ""
	}	
}

Re: Convert Numerical Currency Into Words

Posted: 05 Feb 2023, 00:50
by AlFlo
mikeyww, thank you ... my apologies but I haven't made the move to AHK 2.0 yet.

Re: Convert Numerical Currency Into Words

Posted: 05 Feb 2023, 00:53
by AlFlo
gmoises, looks very promising. But no matter what number I test, it says "no cents".

Re: Convert Numerical Currency Into Words

Posted: 05 Feb 2023, 07:56
by mikeyww
A v1 version is below. One could then parse the string for dollars and cents, generate the two function calls, and add the numbers.

Code: Select all

; This script converts words to a number
#Requires AutoHotkey v1.1.33
MsgBox % wordsToNum("One Million Eight Hundred and Seventy-Six Thousand Five Hundred and Forty-Three")

wordsToNum(str) {
 Static tens     := {"ten"  : 10, "twenty" : 20, "thirty": 30, "forty" : 40, "fifty": 50
                   , "sixty": 60, "seventy": 70, "eighty": 80, "ninety": 90}
      , ones     := {"one": 1, "two"  : 2, "three": 3, "four": 4, "five": 5
                   , "six": 6, "seven": 7, "eight": 8, "nine": 9}
      , place    := {"million": 1000000, "thousand": 1000, "hundred": 100}
      , tensStr  := "", onesStr := ""
 If !tensStr
  For word in tens
   tensStr .= (tensStr = "" ? "" : "|") word
 If !onesStr
  For word in ones
   onesStr .= (onesStr = "" ? "" : "|") word
 str := StrReplace(Format("{:L}", str), " and ", " ")
 For each, pl in ["million", "thousand", "hundred"] {
  RegExMatch(str, "i)((.+)\h+" pl ")?(\h*(.*))?", m)
  If m2
   Return ((n1 := wordsToNum(m2)) ? n1 * place[pl] : 0) + ((n2 := wordsToNum(m4)) ? n2 : 0)
 }
 RegExMatch(m4, "i)(" tensStr ")?[- ]?(" onesStr ")?", m)
 Return (tens.HasKey(m1) ? tens[m1] : 0) + (ones.HasKey(m2) ? ones[m2] : 0)
}

Re: Convert Numerical Currency Into Words

Posted: 05 Feb 2023, 13:14
by AlFlo
Wow, thank you mikeyww!!!

Re: Convert Numerical Currency Into Words

Posted: 05 Feb 2023, 13:40
by mikeyww
Numbers between 11 and 19 might need some additions here!

Re: Convert Numerical Currency Into Words

Posted: 05 Feb 2023, 13:56
by AlphaBravo

Re: Convert Numerical Currency Into Words

Posted: 05 Feb 2023, 14:07
by mikeyww
Number to words is fairly straightforward. Words to number gets more challenging!

Re: Convert Numerical Currency Into Words

Posted: 05 Feb 2023, 16:23
by AlFlo
gmoises wrote:
04 Feb 2023, 22:15
Corrected a bug in thr get cents part

Code: Select all

N := "123456789.999"
MsgBox % SpellNumber(N)

SpellNumber(Num) {
	Place := [" ", " Thousand ", " Million ", " Billion ", " Trillion "]
	Num := Trim(Num)
	
	; get cents
	If DecimalPoint := InStr(Num, ".")
	{	Cen := Tens(SubStr("00" . SubStr(Num, DecimalPoint + 1), -1))
		Num := SubStr(Num, 1, DecimalPoint - 1)
	}
	
	Cnt := 1
	While Num != ""
	{	h := Hundreds(SubStr(Num, -2))
		If h
			Dollars := h . Place[Cnt] . Dollars
		Num := StrLen(Num) > 3 ? SubStr(Num, 1, -3) : ""
		++Cnt
	}
	
	Switch Cen
	{	Case "":
			Cents := " and No Cents"
		Case "One":
			Cents := " and One Cent"
		Default:
			Cents := " and " . Cen . " Cents"
	}
	Return, StrReplace(Dollars . Cents, "  ", " ")
}

; get hundreds
Hundreds(Num) {
	If (Num = 0)
		Return, ""
	Num := SubStr("000" . Num, -2)
	If SubStr(Num, 1, 1) != "0"
		Ret := Digits(SubStr(Num, 1, 1)) . " Hundred "
	If SubStr(Num, 2, 1) != "0"
		Return, Ret . Tens(SubStr(Num, 2))
	Else
		Return, Ret . Digits(SubStr(Num, 3))
}

; get tens
Tens(Num) {
	If (Num > 9 and Num < 20)
		Switch Num
		{	Case 10: Return, "Ten"
			Case 11: Return, "Eleven"
			Case 12: Return, "Twelve"
			Case 13: Return, "Thirteen"
			Case 14: Return, "Fourteen"
			Case 15: Return, "Fifteen"
			Case 16: Return, "Sixteen"
			Case 17: Return, "Seventeen"
			Case 18: Return, "Eighteen"
			Case 19: Return, "Nineteen"
		}
	Else
		Switch SubStr(Num, 1, 1)
		{	Case 2: Ret := "Twenty "
			Case 3: Ret := "Thirty "
			Case 4: Ret := "Forty "
			Case 5: Ret := "Fifty "
			Case 6: Ret := "Sixty "
			Case 7: Ret := "Seventy "
			Case 8: Ret := "Eighty "
			Case 9: Ret := "Ninety "
		}
	Return, Ret . Digits(SubStr(Num, 2, 1))
}

Digits(Num) {
	Switch Num
	{	Case 1: Return, "One"
		Case 2: Return, "Two"
		Case 3: Return, "Three"
		Case 4: Return, "Four"
		Case 5: Return, "Five"
		Case 6: Return, "Six"
		Case 7: Return, "Seven"
		Case 8: Return, "Eight"
		Case 9: Return, "Nine"
		Default: Return, ""
	}	
}
gmoises, your script is getting close and this is getting exciting! You did fix the cents, but there is something off with the dollar calculations. For example, when I have N := "7,123,456,789.55", I get the following result:
Test Result.png
Test Result.png (2.84 KiB) Viewed 1021 times
In other words, it shows "Seven Trillion Hundred Twelve Billion Three Hundred Four Million Five Hundred Sixty Thousand Seven Hundred Eighty Nine and Fifty Five Cents " when it should be "Seven Billion One Hundred Twenty-Three Million Four Hundred Fifty-Six Thousand Seven Hundred Eighty-Nine Dollars and Fifty-Five Cents.

Re: Convert Numerical Currency Into Words

Posted: 05 Feb 2023, 18:45
by AlFlo
The AHK script works perfectly on many numbers, but fails on some large numbers.

Re: Convert Numerical Currency Into Words

Posted: 06 Feb 2023, 01:42
by AlFlo
gmoises,

Your revised script seems to work really well. Thanks!!!