A simple python script that translates an integer to plain English.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | import sys, string as str
words = {
1 : 'one',
2 : 'two',
3 : 'three',
4 : 'four',
5 : 'five',
6 : 'six',
7 : 'seven',
8 : 'eight',
9 : 'nine',
10 : 'ten',
11 : 'eleven',
12 : 'twelve',
13 : 'thirteen',
14 : 'fourteen',
15 : 'fifteen',
16 : 'sixteen',
17 : 'seventeen',
18 : 'eighteen',
19 : 'nineteen'
}
tens = [
'',
'twenty',
'thirty',
'forty',
'fifty',
'sixty',
'seventy',
'eighty',
'ninety',
]
placeholders = [
'',
'thousand',
'million',
'billion',
'trillion',
'quadrillion'
]
# segMag = segment magnitude (starting at 1)
def convertTrio(number):
if int(number) < 100:
return convertDuo(number[1:3])
else:
return ' '.join([ words[int(number[0])], 'hundred', convertDuo(number[1:3]) ])
def convertDuo(number):
#if teens or less
if int(number[0]) <= 1:
return words[int(number)]
#twenty-five
else:
return ''.join([tens[int(number[0]) - 1], '-', words[int(number[1])]])
if __name__ == "__main__":
string = []
numeralSegments = []
numeral = sys.argv[1]
# left-pad number with zeros to make its length a multiple of 3
if len(numeral) % 3 > 0:
numeral = str.zfill( numeral, (3 - (len(numeral) % 3)) + len(numeral) )
# split number into lists, grouped in threes
for i in range (len(numeral), 0, -3):
numeralSegments.append(numeral[i-3:i])
# for every segment, convert to trio word and append thousand, million, etc depending on magnitude
for i in range (len(numeralSegments)):
string.append(convertTrio(numeralSegments[i]) + ' ' + placeholders[i])
# reverse the list of strings before concatenating to commas
string.reverse()
print ', '.join(string)
|
critique appreciated
Typo on line 58?
Litle bug (using pyhon 2.4.5 on Linux) : python recipe-576577-1.py 100 Traceback (most recent call last): File "recipe-576577-1.py", line 99, in ? string.append(convertTrio(numeralSegments[i]) + ' ' + placeholders[i]) File "recipe-576577-1.py", line 71, in convertTrio return ' '.join([ words[int(number[0])], 'hundred', convertDuo(number[1:3]) ]) File "recipe-576577-1.py", line 77, in convertDuo return words[int(number)] KeyError: 0
I wrote one of these a couple years ago. It's 40% faster than num2words given a 10 digit number as input, and possibly has fewer errors. A clever programmer will extend this to work with decimal objects so that we can play with __format__ and __str__ in derived classes. Thanks.
==> Logic error identified by sebastien.renard. Try numbers input like this---
$ python number_as_word.py 1000 $ python number_as_word.py 1000567
==> Include module __doc__ string that tells how to use program.
==> Well enough written that extending program to include the zero case was trivial.
$ python number_as_word.py 0
This reduces the impact of the logic error.
==> Write "if len(numeral) % 3:" instead of "if len(numeral) % 3 > 3:"
Would you write "if (a == b) is True:"? Well, that sort of thing is common but it doesn't work for me.
==> Don't change name of string module. string module is useful for its character lists, like punctuation. String objects contain the methods, as does the str type (or class, I use python 3). zfill thusly:
==> Avoid overwriting library module names or builtin names. I changed the name of the string variable.
==> Use comprehensions.
==> Write a function so the code can be used as a module.
For what it's worth, my version runs two and a half percent more slowly than does yours. Oh well!
Thank you all for the excellent feedback. I'll make the suggested changes, but more importantly, you've given me ideas on how to become a better pythoner. Cheers!