77

I'm trying to tell Python to convert integers into words.

Example: (using the song 99 bottles of beer on the wall)

I used this code to write the program:

for i in range(99,0,-1):
    print i, "Bottles of beer on the wall,"
    print i, "bottles of beer."
    print "Take one down and pass it around,"
    print i-1, "bottles of beer on the wall."
    print

But I cannot figure out how to write the program so that the words (i.e. Ninety nine, Ninety eight, etc.) will be displayed instead of the numbers.

I have been wracking my head in the python book I have, I understand that maybe I just do not understand for/if/elif/else loops yet but I'm just spinning my wheels.

Could anyone provide any insight? I'm not looking for a direct answer, although that might help me see my problem, just anything to point me in the right direction would be great.

11
  • 3
    for, if, elif and else aren't really loops, they are statements Commented Jan 24, 2012 at 4:58
  • Are you only interested in solutions range(99, 0, -1)? Or looking for something more general? Commented Jan 24, 2012 at 5:00
  • possible duplicate of Code Golf: Number to Words Commented Jan 24, 2012 at 5:02
  • are you going to use this for something more useful than to sing a song? Commented Jan 24, 2012 at 5:02
  • 6
    @julio.alegria: That might discourage new learners... It's good that one is trying to solve problems(unless he/she wants it for the sake of getting homework done.) Commented Jan 24, 2012 at 5:44

17 Answers 17

92

The inflect package can do this.

https://pypi.python.org/pypi/inflect

$ pip install inflect

and then:

>>>import inflect
>>>p = inflect.engine()
>>>p.number_to_words(99)
ninety-nine
Sign up to request clarification or add additional context in comments.

3 Comments

@DuffJ num2words, which apparently supersedes PyNum2Word, can also be installed via pip. So can PyNum2Word.
What's the difference between inflect and num2words?
In my experience, num2words is much faster than inflect.
44

Use pynum2word module that can be found at sourceforge

>>> import num2word
>>> num2word.to_card(15)
'fifteen'
>>> num2word.to_card(55)
'fifty-five'
>>> num2word.to_card(1555)
'one thousand, five hundred and fifty-five'

1 Comment

This package has been superseded by num2words.
38

Here's a way to do it in Python 3:

"""Given an int32 number, print it in English."""
def int_to_en(num):
    d = { 0 : 'zero', 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' }
    k = 1000
    m = k * 1000
    b = m * 1000
    t = b * 1000

    assert(0 <= num)

    if (num < 20):
        return d[num]

    if (num < 100):
        if num % 10 == 0: return d[num]
        else: return d[num // 10 * 10] + '-' + d[num % 10]

    if (num < k):
        if num % 100 == 0: return d[num // 100] + ' hundred'
        else: return d[num // 100] + ' hundred and ' + int_to_en(num % 100)

    if (num < m):
        if num % k == 0: return int_to_en(num // k) + ' thousand'
        else: return int_to_en(num // k) + ' thousand, ' + int_to_en(num % k)

    if (num < b):
        if (num % m) == 0: return int_to_en(num // m) + ' million'
        else: return int_to_en(num // m) + ' million, ' + int_to_en(num % m)

    if (num < t):
        if (num % b) == 0: return int_to_en(num // b) + ' billion'
        else: return int_to_en(num // b) + ' billion, ' + int_to_en(num % b)

    if (num % t == 0): return int_to_en(num // t) + ' trillion'
    else: return int_to_en(num // t) + ' trillion, ' + int_to_en(num % t)

    raise AssertionError('num is too large: %s' % str(num))

And the result is:

0 zero
3 three
10 ten
11 eleven
19 nineteen
20 twenty
23 twenty-three
34 thirty-four
56 fifty-six
80 eighty
97 ninety-seven
99 ninety-nine
100 one hundred
101 one hundred and one
110 one hundred and ten
117 one hundred and seventeen
120 one hundred and twenty
123 one hundred and twenty-three
172 one hundred and seventy-two
199 one hundred and ninety-nine
200 two hundred
201 two hundred and one
211 two hundred and eleven
223 two hundred and twenty-three
376 three hundred and seventy-six
767 seven hundred and sixty-seven
982 nine hundred and eighty-two
999 nine hundred and ninety-nine
1000 one thousand
1001 one thousand, one
1017 one thousand, seventeen
1023 one thousand, twenty-three
1088 one thousand, eighty-eight
1100 one thousand, one hundred
1109 one thousand, one hundred and nine
1139 one thousand, one hundred and thirty-nine
1239 one thousand, two hundred and thirty-nine
1433 one thousand, four hundred and thirty-three
2000 two thousand
2010 two thousand, ten
7891 seven thousand, eight hundred and ninety-one
89321 eighty-nine thousand, three hundred and twenty-one
999999 nine hundred and ninety-nine thousand, nine hundred and ninety-nine
1000000 one million
2000000 two million
2000000000 two billion

2 Comments

Is there a way to do this with recursion? User puts in an int, N, as a parameter of a function and the program will print out the text? N is less than 1000000 in this case?
Nice! Wouldn't 1017 = one thousand and seventeen and similar be better?
23

We adapted an existing nice solution (ref) for converting numbers to words as follows:

def numToWords(num,join=True):
    '''words = {} convert an integer number into words'''
    units = ['','one','two','three','four','five','six','seven','eight','nine']
    teens = ['','eleven','twelve','thirteen','fourteen','fifteen','sixteen', \
             'seventeen','eighteen','nineteen']
    tens = ['','ten','twenty','thirty','forty','fifty','sixty','seventy', \
            'eighty','ninety']
    thousands = ['','thousand','million','billion','trillion','quadrillion', \
                 'quintillion','sextillion','septillion','octillion', \
                 'nonillion','decillion','undecillion','duodecillion', \
                 'tredecillion','quattuordecillion','sexdecillion', \
                 'septendecillion','octodecillion','novemdecillion', \
                 'vigintillion']
    words = []
    if num==0: words.append('zero')
    else:
        numStr = '%d'%num
        numStrLen = len(numStr)
        groups = (numStrLen+2)/3
        numStr = numStr.zfill(groups*3)
        for i in range(0,groups*3,3):
            h,t,u = int(numStr[i]),int(numStr[i+1]),int(numStr[i+2])
            g = groups-(i/3+1)
            if h>=1:
                words.append(units[h])
                words.append('hundred')
            if t>1:
                words.append(tens[t])
                if u>=1: words.append(units[u])
            elif t==1:
                if u>=1: words.append(teens[u])
                else: words.append(tens[t])
            else:
                if u>=1: words.append(units[u])
            if (g>=1) and ((h+t+u)>0): words.append(thousands[g]+',')
    if join: return ' '.join(words)
    return words

#example usages:
print numToWords(0)
print numToWords(11)
print numToWords(110)
print numToWords(1001000025)
print numToWords(123456789012)

results:

zero
eleven
one hundred ten
one billion, one million, twenty five
one hundred twenty three billion, four hundred fifty six million, seven hundred
eighty nine thousand, twelve

Note that it works for integer numbers. Nevertheless it is trivial to divide a float number into two integer parts.

2 Comments

'quindecillion' to be added in list thousands after 'quattuordecillion' .
very nice, on python 3 "groups" needs to be cast to int
10

Well, the dead-simple way to do it is to make a list of all the numbers you're interested in:

numbers = ["zero", "one", "two", "three", "four", "five", ... 
           "ninety-eight", "ninety-nine"]

(The ... indicates where you'd type the text representations of other numbers. No, Python isn't going to magically fill that in for you, you'd have to type all of them to use that technique.)

And then to print the number, just print numbers[i]. Easy peasy.

Of course, that list is a lot of typing, so you might wonder about an easy way to generate it. English unfortunately has a lot of irregularities so you'd have to manually put in the first twenty (0-19), but you can use regularities to generate the rest up to 99. (You can also generate some of the teens, but only some of them, so it seems easiest to just type them in.)

numbers = "zero one two three four five six seven eight nine".split()
numbers.extend("ten eleven twelve thirteen fourteen fifteen sixteen".split())
numbers.extend("seventeen eighteen nineteen".split())
numbers.extend(tens if ones == "zero" else (tens + "-" + ones) 
    for tens in "twenty thirty forty fifty sixty seventy eighty ninety".split()
    for ones in numbers[0:10])

print numbers[42]  # "forty-two"

Another approach is to write a function that puts together the correct string each time. Again you'll have to hard-code the first twenty numbers, but after that you can easily generate them from scratch as needed. This uses a little less memory (a lot less once you start working with larger numbers).

2 Comments

There are other posts here that demonstrate 3rd modules that can be used, and some users have posted algorithms that don't use 3rd party modules. There's no need to type out every number like this.
@WayneWorkman Yeah, but if you don't need to convert numbers up to quattuordecillion or whatever than this solution is simple and elegant.
6

You can use the python-n2w library, Just do

pip install n2w

then simply

print(n2w.convert(your-number-here))

5 Comments

n2w currently does not converts the teens correctly.
@hawkjo Thanks for the feedback, could you please provide with an example.
Sure. 14 -> 'forteen' (spelling), 15 -> 'sixteen', 16 -> 'seventeen', 17 -> 'eighteen', 18 -> 'nineteen', 19 -> ' '
@hawkjo thanks for pointing this out, this issue seems to be now resolved :)
I know this is an old answer, but you should make it clear that this is your library in the answer to avoid accusations of spam.
5

And here comes my solution :) It is various of earlier solutions, but developed on my own - maybe somebody enjoy it more then other propositions.

TENS = {30: 'thirty', 40: 'forty', 50: 'fifty', 60: 'sixty', 70: 'seventy', 80: 'eighty', 90: 'ninety'}
ZERO_TO_TWENTY = (
    'zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten',
    'eleven', 'twelve', 'thirteen', 'fourteen', 'fifteen', 'sixteen', 'seventeen', 'eighteen', 'nineteen', 'twenty'
)

def number_to_english(n):
    if any(not x.isdigit() for x in str(n)):
        return ''

    if n <= 20:
        return ZERO_TO_TWENTY[n]
    elif n < 100 and n % 10 == 0:
        return TENS[n]
    elif n < 100:
        return number_to_english(n - (n % 10)) + ' ' + number_to_english(n % 10)
    elif n < 1000 and n % 100 == 0:
        return number_to_english(n / 100) + ' hundred'
    elif n < 1000:
        return number_to_english(n / 100) + ' hundred ' + number_to_english(n % 100)
    elif n < 1000000:
        return number_to_english(n / 1000) + ' thousand ' + number_to_english(n % 1000)

    return ''

It is recoursive solution and can be easily expand for bigger numbers

Comments

4

This does the job without any library. Used recursion and it is Indian style. -- Ravi.

def spellNumber(no):
    # str(no) will result in  56.9 for 56.90 so we used the method which is given below.
    strNo = "%.2f" %no
    n = strNo.split(".")
    rs = numberToText(int(n[0])).strip()
    ps =""
    if(len(n)>=2):
        ps = numberToText(int(n[1])).strip()
        rs = "" + ps+ " paise"  if(rs.strip()=="") else  (rs + " and " + ps+ " paise").strip()
    return rs
print(spellNumber(0.67))
print(spellNumber(5858.099))
print(spellNumber(5083754857380.50))    

def numberToText(no):
    ones = " ,one,two,three,four,five,six,seven,eight,nine,ten,eleven,tweleve,thirteen,fourteen,fifteen,sixteen,seventeen,eighteen,nineteen,twenty".split(',')
    tens = "ten,twenty,thirty,fourty,fifty,sixty,seventy,eighty,ninety".split(',')
    text = ""
    if len(str(no))<=2:
        if(no<20):
            text = ones[no]
        else:
            text = tens[no//10-1] +" " + ones[(no %10)]
    elif len(str(no))==3:
        text = ones[no//100] +" hundred " + numberToText(no- ((no//100)* 100))
    elif len(str(no))<=5:
        text = numberToText(no//1000) +" thousand " + numberToText(no- ((no//1000)* 1000))
    elif len(str(no))<=7:
        text = numberToText(no//100000) +" lakh " + numberToText(no- ((no//100000)* 100000))
    else:
        text = numberToText(no//10000000) +" crores " + numberToText(no- ((no//10000000)* 10000000))
    return text

Comments

3

It sound like you'll need to use an array, where num[1] = "one", num[2] = "two", and so on. Then you can loop through each like you already are and

num = array(["one","two","three","four","five","six","seven","eight","nine","ten"])
for i in range(10,0,-1):
    print num[i], "Bottles of beer on the wall,"
    print num[i], "bottles of beer."
    print "Take one down and pass it around,"
    print num[i-1], "bottles of beer on the wall."
    print ""

Comments

3

Here is refactored version of several code examples posted above (mostly code pasted by "developer".

def int2words(num):
    """Given an int32 number, print it in English.

    Parameters
    ----------
    num : int

    Returns
    -------
    words : str
    """
    assert (0 <= num)
    d = {
        0: 'zero', 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'
    }
    h = [100, 'hundred', 'hundred and']
    k = [h[0] * 10, 'thousand', 'thousand,']
    m = [k[0] * 1000, 'million', 'million,']
    b = [m[0] * 1000, 'billion', 'billion,']
    t = [b[0] * 1000, 'trillion', 'trillion,']
    if num < 20:
        return d[num]
    if num < 100:
        div_, mod_ = divmod(num, 10)
        return d[num] if mod_ == 0 else d[div_ * 10] + '-' + d[mod_]
    else:
        if num < k[0]:
            divisor, word1, word2 = h
        elif num < m[0]:
            divisor, word1, word2 = k
        elif num < b[0]:
            divisor, word1, word2 = m
        elif num < t[0]:
            divisor, word1, word2 = b
        else:
            divisor, word1, word2 = t
        div_, mod_ = divmod(num, divisor)
        if mod_ == 0:
            return '{} {}'.format(int2words(div_), word1)
        else:
            return '{} {} {}'.format(int2words(div_), word2, int2words(mod_))

Comments

3

I would solve this problem simply by doing that:

numberText = {
    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',
    100: 'hundred', 1000: 'thousand', 1000000: 'million'
}


def numberToEnglishText(n):
    if n == 0:
        return 'zero'
    if n < 0:
        return 'negative ' + numberToEnglishText(-n)

    result = ''

    for num in sorted(numberText.keys(), reverse=True):
        count = int(n/num)

        if (count < 1):
            continue

        if (num >= 100):
            result += numberToEnglishText(count) + ' '

        result += numberText[num]
        n -= count * num
        if (n > 0):
            result += ' '

    return result

Comments

2

Code for this:

>>>def handel_upto_99(number):
predef={0:"zero",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:"fourty",50:"fifty",60:"sixty",70:"seventy",80:"eighty",90:"ninety",100:"hundred",100000:"lakh",10000000:"crore",1000000:"million",1000000000:"billion"}
if number in predef.keys():
    return predef[number]
else:
    return predef[(number/10)*10]+' '+predef[number%10]

>>>def return_bigdigit(number,devideby):
predef={0:"zero",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:"fourty",50:"fifty",60:"sixty",70:"seventy",80:"eighty",90:"ninety",100:"hundred",1000:"thousand",100000:"lakh",10000000:"crore",1000000:"million",1000000000:"billion"}
if devideby in predef.keys():
    return predef[number/devideby]+" "+predef[devideby]
else:
    devideby/=10
    return handel_upto_99(number/devideby)+" "+predef[devideby]

>>>def mainfunction(number):
dev={100:"hundred",1000:"thousand",100000:"lakh",10000000:"crore",1000000000:"billion"}
if number is 0:
    return "Zero"
if number<100:
    result=handel_upto_99(number)

else:
    result=""
    while number>=100:
        devideby=1
        length=len(str(number))
        for i in range(length-1):
            devideby*=10
        if number%devideby==0:
            if devideby in dev:
                return handel_upto_99(number/devideby)+" "+ dev[devideby]
            else:
                return handel_upto_99(number/(devideby/10))+" "+ dev[devideby/10]
        res=return_bigdigit(number,devideby)
        result=result+' '+res
        if devideby not in dev:
            number=number-((devideby/10)*(number/(devideby/10)))
        number=number-devideby*(number/devideby)

    if number <100:
        result = result + ' '+ handel_upto_99(number)
return result

result:

>>>mainfunction(12345)
' twelve thousand three hundred fourty five'
>>>mainfunction(2000)
'two thousand'

Comments

2

This works for too the first 1000 numbers (Python 3). Beginner solution to the problem but a solution nonetheless...

first_nums = ["", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve",
              "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"]
tens = ["ten", "twenty", "thirty","forty","fifty", "sixty","seventy","eighty","ninety"]

for num in range(1,1001):
    if num < 20:
        print(first_nums[num])
    elif num < 100 and num % 10 == 0:
        print(tens[int(num/10 - 1)])
    elif num < 1000 and num % 100 == 0:
        print(first_nums[int(num/100)] + " hundred")
    elif num == 1000:
        print("one thousand")
    elif num < 100 and num % 10 != 0:
        print(tens[int(num//10 - 1)] + " " + first_nums[int(num%10)])
    elif num < 1000:
        if num%100 < 20:
            print(first_nums[int(num//100)] + " hundred and " + first_nums[num%100])
        else:
            print(first_nums[int(num//100)] + " hundred and " + tens[int(num%100//10 - 1)] + " " + first_nums[int(num%10)])

Comments

0

You have to use a dictionnary/array. For example :

 to_19= ['zero','one','two','three','four','five','six','seven','eight','nine'..'nineteen']
 tens = ['twenty'...'ninety']

And you could generate the string of a number by doing, for example :

 if len(str(number)) == 2 and  number > 20:
       word_number = tens[str(number)[0]]+' '+units[str(number)[0]]

You have to check if the last figure is not a zero and so on.. classic value checking.

It reminds a project euler challenge (problem 17).. you should try to find some solutions about it

Hope it helps

Comments

0
#This valid till 4 digit number
numbers={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', 100:'hundred', 1000:'thousand'}

def my_fun(num):
    list = []
    num_len = len(str(num)) - 1
    while num_len > 0 and num > 0:
       while num_len > 0 and num > 0:
        if num in numbers and num < 1000:
            list.append(numbers[num])
            num_len = 0
        elif num < 100:
            list.extend([numbers[num - num%10], numbers[num%10]])
            num_len = 0
        else:
            quotent = num//10**num_len # 4567//1000= 4
            num = num % 10**num_len #4567%1000 =567
            if quotent != 0 :
                list.append(numbers[quotent])
                list.append(numbers[10**num_len])
            else:
                list.append(numbers[num])
            num_len -= 1
    return ' '.join(list)

1 Comment

Fails for single digit integers like 5, 6.
0

I created a quick version of the number-to-word converter in Python 3 that works in the range [0-99] without using any library. This version might become handy if you do not need higher values.

# converts number-to-word in range [0-99]
def number_to_word(num):
    sub_twenty = ('zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight',
                  'nine', 'ten', 'eleven', 'twelve', 'thirteen', 'fourteen', 'fifteen',
                  'sixteen', 'seventeen', 'eighteen', 'nineteen')
    tens = {20: 'twenty', 30: 'thirty', 40: 'forty', 50: 'fifty', 
            60: 'sixty', 70: 'seventy', 80: 'eighty', 90: 'ninety'}

    # if it is less than 20 directly converts its value from the list
    if num < 20:
        return sub_twenty[num]

    # if its order of 10 gets from the dict
    elif num % 10 == 0:
        return tens[num]

    # if it has any value in units digit gets both
    else:
        quo = num // 10             # quotient
        quo = tens[quo * 10]        # scale and get value from dict

        rem = num % 10              # remainder
        rem = sub_twenty[rem]       # get its word format
        return quo + " " + rem

Comments

0

If you are using django, you can use django.contrib.humanize.apnumber which follows the Associated Press method of conversion where numbers <10 get converted to words and anything greater is returned as digits.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.