-
Notifications
You must be signed in to change notification settings - Fork 0
/
num2text.py
124 lines (115 loc) · 2.55 KB
/
num2text.py
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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
import math
# Tokens from 1000 and up
_PRONOUNCE = [
'vigintillion',
'novemdecillion',
'octodecillion',
'septendecillion',
'sexdecillion',
'quindecillion',
'quattuordecillion',
'tredecillion',
'duodecillion',
'undecillion',
'decillion',
'nonillion',
'octillion',
'septillion',
'sextillion',
'quintillion',
'quadrillion',
'trillion',
'billion',
'million ',
'thousand ',
''
]
# Tokens up to 90
_SMALL = {
'0' : '',
'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',
'20' : 'twenty',
'30' : 'thirty',
'40' : 'forty',
'50' : 'fifty',
'60' : 'sixty',
'70' : 'seventy',
'80' : 'eighty',
'90' : 'ninety'
}
def get_num(num):
'''Get token <= 90, return '' if not matched'''
return _SMALL.get(num, '')
def triplets(l):
'''Split list to triplets. Pad last one with '' if needed'''
res = []
for i in range(int(math.ceil(len(l) / 3.0))):
sect = l[i * 3 : (i + 1) * 3]
if len(sect) < 3: # Pad last section
sect += [''] * (3 - len(sect))
res.append(sect)
return res
def norm_num(num):
"""Normelize number (remove 0's prefix). Return number and string"""
n = int(num)
return n, str(n)
def small2eng(num):
'''English representation of a number <= 999'''
n, num = norm_num(num)
hundred = ''
ten = ''
if len(num) == 3: # Got hundreds
hundred = get_num(num[0]) + ' hundred'
num = num[1:]
n, num = norm_num(num)
if (n > 20) and (n != (n / 10 * 10)): # Got ones
tens = get_num(num[0] + '0')
ones = get_num(num[1])
ten = tens + ' ' + ones
else:
ten = get_num(num)
if hundred and ten:
return hundred + ' ' + ten
#return hundred + ' and ' + ten
else: # One of the below is empty
return hundred + ten
#FIXME: Currently num2eng(1012) -> 'one thousand, twelve'
# do we want to add last 'and'?
def num2text(num):
'''English representation of a number'''
num = str(long(num)) # Convert to string, throw if bad number
if (len(num) / 3 >= len(_PRONOUNCE)): # Sanity check
raise ValueError('Number too big')
if num == '0': # Zero is a special case
return 'zero'
# Create reversed list
x = list(num)
x.reverse()
pron = [] # Result accumolator
ct = len(_PRONOUNCE) - 1 # Current index
for a, b, c in triplets(x): # Work on triplets
p = small2eng(c + b + a)
if p:
pron.append(p + ' ' + _PRONOUNCE[ct])
ct -= 1
# Create result
pron.reverse()
return ', '.join(pron)