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
\$\endgroup\$
  • \$\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 Jan 13 '14 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 Jan 13 '14 at 21:55
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.

\$\endgroup\$
  • \$\begingroup\$ Your very last else shouldn't append 2 elements but insert them at once with a - as separation \$\endgroup\$ – oliverpool Nov 27 '15 at 14:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.