# Putting numbers into words

I have some embarrassingly long code which puts into words any number up into the trillions. As a newbie, and understanding that shorter, non-repetitive code is best, I am looking for suggestions on how to reduce this code to a respectable quantity. I realize that there is a lot of repetition in it. However, depending on the number being evaluated, the math looks a little different with each rep, so I am not sure if I can reduce that. I have tried rewriting it solely as an if/else (without the recursion) but it quickly becomes just as bad if not worse.

class :: Fixnum

def in_words(number)

if number < 0  # No negative numbers.
return 'Please enter a number that isn\'t negative.'
end

if number == 0
return 'zero'
end

numString = ''  # This is the string we will return.

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

#-----------------------------------------trillions

left = number
write = left/1000000000000
left = left - (write*1000000000000)

if number > 999999999999

if write < 10 #1,00 - 9,000
millions  = onesPlace[write - 1]
numString = numString + millions + ' trillion'
end

if (write > 9) && (write < 20) #10,000 - 19,000
if write == 10
millions = tensPlace[write - 10]
numString = numString + millions + ' trillion'
else
millions = teenagers[write - 11] #11 because the length of teenagers is only 9 so 15-11 = 4 and 'thirteen' is in
numString = numString + millions + ' trillion'
end
end

if (write > 19) && (write < 1000) #here i have to use recursion to get the first two/three digets --> 19,000,000 - 999,000,000
millions = in_words(write)
numString = numString + millions + ' trillion'
end

if left > 0
numString = numString + ' '
end

#-----------------------------------------billions
#left = number
write = left/1000000000
left = left - (write*1000000000)

if number > 999999999

if write < 10 #1,00 - 9,000
millions  = onesPlace[write - 1]
numString = numString + millions + ' billion'
end

if (write > 9) && (write < 20) #10,000 - 19,000
if write == 10
millions = tensPlace[write - 10]
numString = numString + millions + ' billion'
else
millions = teenagers[write - 11] #11 because the length of teenagers is only 9 so 15-11 = 4 and 'thirteen' is in
numString = numString + millions + ' billion'
end
end

if (write > 19) && (write < 1000) #here i have to use recursion to get the first two/three digets --> 19,000,000 - 999,000,000
millions = in_words(write)
numString = numString + millions + ' billion'
end

if left > 0
numString = numString + ' '
end

# ----------------------------------------millions
write = left/1000000
left = left - (write*1000000)

if number > 999999

if write < 10 #1,00 - 9,000
millions  = onesPlace[write - 1]
numString = numString + millions + ' million'
end

if (write > 9) && (write < 20) #10,000 - 19,000
if write == 10
millions = tensPlace[write - 10]
numString = numString + millions + ' million'
else
millions = teenagers[write - 11] #11 because the length of teenagers is only 9 so 15-11 = 4 and 'thirteen' is in
numString = numString + millions + ' million'
end
end

if (write > 19) && (write < 1000) #here i have to use recursion to get the first two/three digets --> 19,000,000 - 999,000,000
millions = in_words(write)
numString = numString + millions + ' million'
end

if left > 0
numString = numString + ' '
end

#-----------------------------------------thousands
write = left/1000
left = left - (write*1000)

if number > 999

if write < 10 #1,00 - 9,000
thousands  = onesPlace[write - 1]
numString = numString + thousands + ' thousand'
end

if (write > 9) && (write < 20) #10,000 - 19,000
if write == 10
thousands = tensPlace[write - 10]
numString = numString + thousands + ' thousand'
else
thousands = teenagers[write - 11] #11 because the length of teenagers is only 9 so 15-11 = 4 and 'thirteen' is in
numString = numString + thousands + ' thousand'
end
end

if (write > 19) && (write < 1000) #here i have to use recursion to get the first two/three digits --> 19,000 - 999,000
thousands = in_words(write)
numString = numString + thousands + ' thousand'
end

if left > 0
numString = numString + ' '
end
end
end
end
end
# ------------- hundreds
write = left/100
left  = left - (write*100)

if write > 0
hundreds  = in_words(write)
numString = numString + hundreds + ' hundred'

if left > 0
numString = numString + ' '
end
end

# ---------------- tens
write = left/10    #stop here and return
#numString = numString +
left  = left - write*10

if write > 0
if ((write == 1) and (left > 0))
numString = numString + teenagers[left-1]
left = 0
else
numString = numString + tensPlace[write-1]
end

if left > 0
numString = numString + '-'
end
end

write = left
left  = 0

if write > 0
numString = numString + onesPlace[write-1]
end

numString
end

end#class

puts 95202824653012.in_words(95202824653012)


Another problem I have with it is that it is a method added to the Fixnum class and I would like to be able to call it directly on self without an argument, for example 3457278.in_words instead of 3457278.in_words(3457278). The problem seems to be that the recursion needs an argument when it is called, and therefore the method needs one. Or is there a way around that?

Rather than rewrite your whole solution, I'll point out more idiomatic ways to do this stuff in Ruby.

## Recursion

You don't need an argument to do recursion, self is enough.

class ::Fixnum
def in_words
# ...
millions = write.in_words
# ...
end
end


## String Arrays

%w{} is handy for making arrays containing one-word strings

ones_place = %{one two three four five six seven eight nine}


## Long Numbers

_ can be used like a comma (or period, if you're European) in long numbers.

billion = 1_000_000_000


For powers of 10, you can also use exponentiation

trillion = 10 ** 12


## Modulus

% gets the remainder of a number after dividing.

write = left / 10 ** 9
left = left % 10 ** 9


## Assignment Shortcut

x = x <op> y can be written as x <op>= y where <op> is any operator.

numString += ' '
left %= 10 ** 9


## Loops

Once you incorporate all of those, you should be able to see how that huge nested if can be turned into a tiny

[12, 9, 6, 3].each do |power|
break if self < 10 ** power
# ...
end

• awesome suggestions! in addition, because of the specific answer to the recursion I will mark this as the answer. I will use your suggestions...cant wait to see how much i can shorten this with them! – HolyMoly Mar 24 '15 at 22:38
• Actually, Code Review (where this got migrated) is not about rewriting code. This advice is fine. It is, however, the place for working code that needs to be refactored. – Mark Thomas Mar 25 '15 at 20:51