hken27
hken27

Reputation: 413

Using Ruby convert numbers to words?

How to convert numbers to words in ruby?

I know there is a gem somewhere. Trying to implement it without a gem. I just need the numbers to words in English for integers. Found this but it is very messy. If you have any idea on how to implement a cleaner easier to read solution please share.

http://raveendran.wordpress.com/2009/05/29/ruby-convert-number-to-english-word/

Here is what I have been working on. But having some problem implementing the scales. The code is still a mess. I hope to make it more readable when it functions properly.

   class Numberswords
    def in_words(n)

    words_hash = {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"}

     scale = [000=>"",1000=>"thousand",1000000=>" million",1000000000=>" billion",1000000000000=>" trillion", 1000000000000000=>" quadrillion"]


    if words_hash.has_key?(n) 
      words_hash[n]

      #still working on this middle part. Anything above 999 will not work
     elsif n>= 1000  
     print  n.to_s.scan(/.{1,3}/) do |number|
            print number
      end



      #print value = n.to_s.reverse.scan(/.{1,3}/).inject([]) { |first_part,second_part| first_part << (second_part == "000" ? "" : second_part.reverse.to_i.in_words) }
      #(value.each_with_index.map { |first_part,second_part| first_part == "" ? "" : first_part + scale[second_part] }-[""]).reverse.join(" ")

    elsif n <= 99
       return [words_hash[n - n%10],words_hash[n%10]].join(" ")
    else
      words_hash.merge!({ 100=>"hundred" })
      ([(n%100 < 20 ? n%100 : n.to_s[2].to_i), n.to_s[1].to_i*10, 100, n.to_s[0].to_i]-[0]-[10])
        .reverse.map { |num| words_hash[num] }.join(" ")
    end
  end
end

#test code
test = Numberswords.new
 print test.in_words(200)

Upvotes: 15

Views: 36967

Answers (7)

rhernando
rhernando

Reputation: 1071

Have you considered humanize ?

https://github.com/radar/humanize

Upvotes: 16

Deepak Mahakale
Deepak Mahakale

Reputation: 23671

Simple answer use humanize gem and you will get desired output

Install it directly

gem install humanize

Or add it to your Gemfile

gem 'humanize'

And you can use it

require 'humanize'

1.humanize       #=> 'one'
345.humanize     #=> 'three hundred and forty-five'
1723323.humanize #=> 'one million, seven hundred and twenty-three thousand, three hundred and twenty-three'

If you are using this in rails you can directly use this

NOTE: As mentioned by sren in the comments below. The humanize method provided by ActiveSupport is different than the gem humanize

Upvotes: 9

dsn raghavendra rao
dsn raghavendra rao

Reputation: 196

def subhundred number

  ones = %w{zero one two three four five six seven eight nine
            ten eleven twelve thirteen fourteen fifteen
            sixteen seventeen eighteen nineteen}

  tens = %w{zero ten twenty thirty **forty** fifty sixty seventy eighty ninety}

  subhundred = number % 100

  return [ones[subhundred]] if subhundred < 20

  return [tens[subhundred / 10]] if subhundred % 10 == 0

  return [tens[subhundred / 10], ones[subhundred % 10]]

end




def subthousand number

  hundreds = (number % 1000) / 100

  tens = number % 100

  s = []

  s = subhundred(hundreds) + ["hundred"] unless hundreds == 0

  s = s + ["and"] unless hundreds == 0 or tens == 0

  s = s + [subhundred(tens)] unless tens == 0


end




def decimals number

  return [] unless number.to_s['.']

  digits = number.to_s.split('.')[1].split('').reverse

  digits = digits.drop_while {|d| d.to_i == 0} . reverse

  digits = digits.map {|d| subhundred d.to_i} . flatten

  digits.empty? ? [] : ["and cents"] + digits

end





def words_from_numbers number

  steps = [""] + %w{thousand million billion trillion quadrillion quintillion sextillion}

  result = []

  n = number.to_i

  steps.each do |step|

    x = n % 1000

    unit = (step == "") ? [] : [step]

    result = subthousand(x) + unit  + result unless x == 0

    n = n / 1000

  end



  result = ["zero"] if result.empty?

  result = result + decimals(number)




  result.join(' ').strip

end






 def words_from_numbers(number)

    ApplicationHelper.words_from_numbers(number)

  end

Upvotes: 0

taimur akhtar
taimur akhtar

Reputation: 151

You can also use the to_words gem.

This Gem converts integers into words.

e.g.

1.to_words # one ,

100.to_words # one hundred ,

101.to_words # one hundred and one

It also converts negative numbers.

Upvotes: 6

NoNonsense
NoNonsense

Reputation: 941

My take on this

def in_words(int)
  numbers_to_name = {
      1000000 => "million",
      1000 => "thousand",
      100 => "hundred",
      90 => "ninety",
      80 => "eighty",
      70 => "seventy",
      60 => "sixty",
      50 => "fifty",
      40 => "forty",
      30 => "thirty",
      20 => "twenty",
      19=>"nineteen",
      18=>"eighteen",
      17=>"seventeen", 
      16=>"sixteen",
      15=>"fifteen",
      14=>"fourteen",
      13=>"thirteen",              
      12=>"twelve",
      11 => "eleven",
      10 => "ten",
      9 => "nine",
      8 => "eight",
      7 => "seven",
      6 => "six",
      5 => "five",
      4 => "four",
      3 => "three",
      2 => "two",
      1 => "one"
    }
  str = ""
  numbers_to_name.each do |num, name|
    if int == 0
      return str
    elsif int.to_s.length == 1 && int/num > 0
      return str + "#{name}"      
    elsif int < 100 && int/num > 0
      return str + "#{name}" if int%num == 0
      return str + "#{name} " + in_words(int%num)
    elsif int/num > 0
      return str + in_words(int/num) + " #{name} " + in_words(int%num)
    end
  end
end



puts in_words(4) == "four"
puts in_words(27) == "twenty seven"
puts in_words(102) == "one hundred two"
puts in_words(38_079) == "thirty eight thousand seventy nine"
puts in_words(82102713) == "eighty two million one hundred two thousand seven hundred thirteen"

Upvotes: 25

Bala
Bala

Reputation: 11244

I am not quite sure, if this works for you. Method can be called like this.

n2w(33123) {|i| puts i unless i.to_s.empty?}

Here is the method ( I have not tested it fully. I think it works upto million. Code is ugly, there is a lot of room for re-factoring. )

def n2w(n)
  words_hash = {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"}
  scale = {3=>"hundred",4 =>"thousand",6=>"million",9=>"billion"}

  if words_hash.has_key?n
    yield words_hash[n] 
  else
    ns = n.to_s.split(//)
      while ns.size > 0      
        if ns.size == 2
            yield("and")
            yield words_hash[(ns.join.to_i) - (ns.join.to_i)%10]            
            ns.shift
        end
        if ns.size > 4
          yield(words_hash[(ns[0,2].join.to_i) - (ns[0,2].join.to_i) % 10])
        else
          yield(words_hash[ns[0].to_i]) 
        end
        yield(scale[ns.size])
        ns.shift
      end
    end
end

Upvotes: 0

Richard Peck
Richard Peck

Reputation: 76774

I can see what you're looking for, and you may wish to check out this StackOverflow post: Number to English Word Conversion Rails

Here it is in summary:

No, you have to write a function yourself. The closest thing to what you want is number_to_human, but that does not convert 1 to One.

Here are some URLs that may be helpful:

http://codesnippets.joyent.com/posts/show/447 http://raveendran.wordpress.com/2009/05/29/ruby-convert-number-to-english-word/ http://deveiate.org/projects/Linguistics/

Upvotes: 1

Related Questions