So I wrote this function to convert a given number to its interpretation in the English language as part of the Project Euler exercises. It works fine, but I sense that it's rather sloppy and inelegant, especially for Python where many things can be done quickly in a couple of lines. Any feedback on how to make this code more beautiful/Pythonic is appreciated!
NUMBER_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",
20 : "twenty",
30 : "thirty",
40 : "forty",
50 : "fifty",
60 : "sixty",
70 : "seventy",
80 : "eighty",
90 : "ninety"
}
def convert_number_to_words(num):
#Works up to 99,999
num = str(num)
analyze = 0
postfix = remainder = None
string = ""
if len(num) > 4:
analyze = int(num[0:2])
remainder = num[2:]
postfix = " thousand "
elif len(num) > 3:
analyze = int(num[0:1])
remainder = num[1:]
postfix = " thousand "
elif len(num) > 2:
analyze = int(num[0:1])
remainder = num[1:]
postfix = " hundred "
if int(remainder) > 0:
postfix += "and "
elif int(num) in NUMBER_WORDS:
analyze = int(num)
else:
analyze = int(num[0:1] + "0")
remainder = num[1:]
postfix = "-"
string = NUMBER_WORDS[analyze]
if postfix is not None:
string += postfix
if remainder is not None and int(remainder) > 0:
return string + convert_number_to_words(remainder)
else:
return string
-
\$\begingroup\$ "And" is normally reserved for writing out fractions. 13,500 would be "thirteen thousand and five hundred" in your example, but would be said as "thirteen thousand five hundred". \$\endgroup\$TyCobb– TyCobb2014年01月13日 21:48:01 +00:00Commented Jan 13, 2014 at 21:48
-
\$\begingroup\$ @TyCobb Ah, good point. Editted. I'm with you that "and" shouldn't be included at all, but it's in the directions of the problem: projecteuler.net/problem=17 \$\endgroup\$asteri– asteri2014年01月13日 21:55:20 +00:00Commented Jan 13, 2014 at 21:55
1 Answer 1
Here's one using modulo %
and list joining that uses your original NUMBER_WORDS
dict:
def int_to_english(n):
english_parts = []
ones = n % 10
tens = n % 100
hundreds = math.floor(n / 100) % 10
thousands = math.floor(n / 1000)
if thousands:
english_parts.append(int_to_english(thousands))
english_parts.append('thousand')
if not hundreds and tens:
english_parts.append('and')
if hundreds:
english_parts.append(NUMBER_WORDS[hundreds])
english_parts.append('hundred')
if tens:
english_parts.append('and')
if tens:
if tens < 20 or ones == 0:
english_parts.append(NUMBER_WORDS[tens])
else:
english_parts.append(NUMBER_WORDS[tens - ones])
english_parts.append(NUMBER_WORDS[ones])
return ' '.join(english_parts)
It works up to 999,999, but could be extended further with a little customisation.
-
\$\begingroup\$ Your very last
else
shouldn't append 2 elements but insert them at once with a-
as separation \$\endgroup\$oliverpool– oliverpool2015年11月27日 14:04:09 +00:00Commented Nov 27, 2015 at 14:04
Explore related questions
See similar questions with these tags.