How to Convert Decimal Numbers to Words with Python

[i=s] 本帖最后由 jieforest 于 2012-6-8 06:23 编辑

It may have been a better idea to have called this this article “How to Convert Floats to Words”, but since I’m talking about currency, I thought using Decimal was more accurate. Anyway, a couple years ago, I wrote about how to convert numbers to Python. The main reason I’m revisiting this topic is because I ended up needing to do it again and I found my own example rather lacking. It doesn’t show how to actually use it to convert something like “10.12″ into “ten dollars and twelve cents”. So I’m going to show you how to do it in this article and then we’ll also look at some of the alternatives that my readers gave me.

Back to the Drawing Board

To start out, we’ll take the original code and add some tests on the end to make sure it works the way we want. Then I’ll show you a slightly different way to go about it. Finally, we will look at two other projects that attempt to do this sort of thing as well.

CODE:

001.'''Convert number to English words
002.\$./num2eng.py 1411893848129211
003.one quadrillion, four hundred and eleven trillion, eight hundred and ninety
004.three billion, eight hundred and forty eight million, one hundred and twenty
005.nine thousand, two hundred and eleven
006.\$
007.
008.Algorithm from http://mini.net/tcl/591
009.'''
010.
011.# modified to exclude the "and" between hundreds and tens - mld
012.
013.__author__ = 'Miki Tebeka '
014.__version__ = '\$Revision: 7281
[/align]

015.
016.# \$Source\$
017.
018.import math
019.
020.# Tokens from 1000 and up
021._PRONOUNCE = [
022.'vigintillion',
023.'novemdecillion',
024.'octodecillion',
025.'septendecillion',
026.'sexdecillion',
027.'quindecillion',
028.'quattuordecillion',
029.'tredecillion',
030.'duodecillion',
031.'undecillion',
032.'decillion',
033.'nonillion',
034.'octillion',
035.'septillion',
036.'sextillion',
037.'quintillion',
039.'trillion',
040.'billion',
041.'million',
042.'thousand',
043.''
044.]
045.
046.# Tokens up to 90
047._SMALL = {
048.'0' : '',
049.'1' : 'one',
050.'2' : 'two',
051.'3' : 'three',
052.'4' : 'four',
053.'5' : 'five',
054.'6' : 'six',
055.'7' : 'seven',
056.'8' : 'eight',
057.'9' : 'nine',
058.'10' : 'ten',
059.'11' : 'eleven',
060.'12' : 'twelve',
061.'13' : 'thirteen',
062.'14' : 'fourteen',
063.'15' : 'fifteen',
064.'16' : 'sixteen',
065.'17' : 'seventeen',
066.'18' : 'eighteen',
067.'19' : 'nineteen',
068.'20' : 'twenty',
069.'30' : 'thirty',
070.'40' : 'forty',
071.'50' : 'fifty',
072.'60' : 'sixty',
073.'70' : 'seventy',
074.'80' : 'eighty',
075.'90' : 'ninety'
076.}
077.
078.def get_num(num):
079.'''Get token <= 90, return '' if not matched'''
080.return _SMALL.get(num, '')
081.
082.def triplets(l):
083.'''Split list to triplets. Pad last one with '' if needed'''
084.res = []
085.for i in range(int(math.ceil(len(l) / 3.0))):
086.sect = l[i * 3 : (i + 1) * 3]
087.if len(sect) < 3: # Pad last section
088.sect += [''] * (3 - len(sect))
089.res.append(sect)
090.return res
091.
092.def norm_num(num):
093."""Normelize number (remove 0's prefix). Return number and string"""
094.n = int(num)
095.return n, str(n)
096.
097.def small2eng(num):
098.'''English representation of a number <= 999'''
099.n, num = norm_num(num)
100.hundred = ''
101.ten = ''
102.if len(num) == 3: # Got hundreds
103.hundred = get_num(num) + ' hundred'
104.num = num[1:]
105.n, num = norm_num(num)
106.if (n > 20) and (n != (n / 10 * 10)): # Got ones
107.tens = get_num(num + '0')
108.ones = get_num(num)
109.ten = tens + ' ' + ones
110.else:
111.ten = get_num(num)
112.if hundred and ten:
113.return hundred + ' ' + ten
114.#return hundred + ' and ' + ten
115.else: # One of the below is empty
116.return hundred + ten
117.
118.def num2eng(num):
119.'''English representation of a number'''
120.num = str(long(num)) # Convert to string, throw if bad number
121.if (len(num) / 3 >= len(_PRONOUNCE)): # Sanity check
122.raise ValueError('Number too big')
123.
124.if num == '0': # Zero is a special case
125.return 'zero '
126.
127.# Create reversed list
128.x = list(num)
129.x.reverse()
130.pron = [] # Result accumolator
131.ct = len(_PRONOUNCE) - 1 # Current index
132.for a, b, c in triplets(x): # Work on triplets
133.p = small2eng(c + b + a)
134.if p:
135.pron.append(p + ' ' + _PRONOUNCE[ct])
136.ct -= 1
137.# Create result
138.pron.reverse()
139.return ', '.join(pron)
140.
141.if __name__ == '__main__':
142.
143.numbers = [1.37, 0.07, 123456.00, 987654.33]
144.for number in numbers:
145.dollars, cents = [int(num) for num in str(number).split(".")]
146.
147.dollars = num2eng(dollars)
148.if dollars.strip() == "one":
149.dollars = dollars + "dollar and "
150.else:
151.dollars = dollars + "dollars and "
152.
153.cents = num2eng(cents) + "cents"
154.print dollars + cents

• 博文量
442
• 访问量
521782