The "professional" approach would be using libraries that already exist. As agtoever mentioned, there's num2words
. So you can do things like:
>>> from num2words import num2words
>>> num2words(42)
forty-two
>>> num2words(42, to='ordinal')
forty-second
>>> num2words(42, lang='fr')
quarante-deux
This library already supports thousand-separators, multiple languages, currencies and other neat stuff you hadn't even considered supporting yet.
As BCdotWEB indicated in the comments, you should check your spelling (ninteen -> nineteen, ninty -> ninety) and write tests. Projects like these are perfect to familiarize yourself with Test Driven Development (TDD). TDD can very roughly be described as 'write tests first, keep writing code till tests pass, repeat`.
Considering you already have the code, I'll cut away portions of it and use the base to somewhat illustrate TDD. We're already doing it the wrong way around (there's code first and tests later instead of vice versa), but I think it gets the message across:
def nToTxt(n):
nums = {0:"", 1:'one', 2: 'two', 3: 'three', 4: 'four', 5: 'five', 6: 'six', 7:
'seven', 8: 'eight', 9: 'nine', 10: 'ten',11: 'eleven', 12: 'twevlve',
13: 'thirteen', 14: 'fourteen', 15: 'fifteen', 16: 'sixteen', 17: 'seventeen',
18: 'eighteen', 19 : 'nineteen'}
tens = {2:'twenty', 3: 'thirty', 4: 'forty', 5: 'fifty', 6: 'sixty', 7: 'seventy',
8: 'eighty', 9: 'ninety'}
if n < 21 :
txt = f"{nums[n]}"
elif n > 20 and n< 100:
txt = f"{tens[int(n/10)]} {nums[n%10]}"
else:
txt = f"{nums[n//100]} hundred {tens[(int(n/10))%10]} {nums[n%10]}"
return(txt)
assert nToTxt(1) == "one"
assert nToTxt(2) == "two"
assert nToTxt(7) == "seven"
assert nToTxt(10) == "ten"
assert nToTxt(19) == "nineteen"
# assert nToTxt(20) == "twenty"
assert nToTxt(21) == "twenty one"
assert nToTxt(22) == "twenty two"
assert nToTxt(24) == "twenty four"
assert nToTxt(28) == "twenty eight"
# assert nToTxt(30) == "thirty"
assert nToTxt(49) == "forty nine"
assert nToTxt(81) == "eighty one"
This is not the best way to write such tests, but it is the easiest way. Especially if you've never written tests before.
assert
checks if the following statement is an expression and whether the expression resolves to True
. Would I for example change the test for 49
to "fourty nine"
instead of "forty nine"
, an AssertionError
is raised.
The tests for 20
and 30
are commented out. The other tests pass, but those do not. There's a problem in the core of your nToTxt
function that fails to handle this case. There are multiple problems here. For starters:
if n < 21 :
Is still true for 20
. It's handled the same way 10
is, but 20
is not in the same nums
dictionary. So this will throw a KeyError
, the program tells you it can not find the entry you're looking for. So, we'll change the program to:
if n < 20 :
txt = f"{nums[n]}"
elif n >= 20 and n < 100:
txt = f"{tens[int(n/10)]} {nums[n%10]}"
This is still wrong. If there are no lookups for nums
remaining, there will still be a trailing space. There are multiple ways to handle this. The two obvious ones are removing the trailing spaces or modifying the string in case n%10
is 0
.
First approach:
if n < 20 :
txt = f"{nums[n]}"
elif n >= 20 and n < 100:
txt = f"{tens[int(n/10)]} {nums[n%10]}"
else:
txt = f"{nums[n//100]} hundred {tens[(int(n/10))%10]} {nums[n%10]}"
return(txt.rstrip(" "))
str.rstrip([chars])
will return a copy of the string with trailing characters removed. There's an lstrip
too, in case you ever want to remove characters from the front of the string.
I'll leave the second approach as an exercise, but you'll want to overhaul the remainder of the function either way. At the moment, nToTxt(0)
is empty. Modifying the dictionary to have it contain zero
will break the rest of your program. Add zero
and modify the rest of your program to handle it properly with extra checks.
{nToTxt(thousands)}thousand
is missing a space. Did you even test this at all? Did you even write tests for it? \$\endgroup\$