4
\$\begingroup\$

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
rolfl
98.1k17 gold badges219 silver badges419 bronze badges
asked Jan 13, 2014 at 21:24
\$\endgroup\$
2
  • \$\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\$ Commented 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\$ Commented Jan 13, 2014 at 21:55

1 Answer 1

4
\$\begingroup\$

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.

answered Jan 14, 2014 at 6:03
\$\endgroup\$
1
  • \$\begingroup\$ Your very last else shouldn't append 2 elements but insert them at once with a - as separation \$\endgroup\$ Commented Nov 27, 2015 at 14:04

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.