David Alan Black wrote:
...
> 
> > I had a need for something similar (though upto a million would have
> > sufficed) a short while ago and wrote an equivalent in Python.  A mechanical
> > transilteration to Ruby is also available:
> >
> > http://www.cs.indiana.edu/~raja/code/Cardinal.py
> > http://www.cs.indiana.edu/~raja/code/Cardinal.rb
> 
> Haven't looked, but will.  Meanwhile, I've put my Perl version (minus
> the hyphens) at <http://icarus.shu.edu/dblack/inttoeng.pl>.  (The Perl
> version also does ordinal numbers -- "twenty-second" etc.)
> 
> David
> 

I couldn't get to your perl script, but I found the others, as well as
seeing the ones posted to this list.

I have been impressed with the solutions.

I decided to spend some time honing another solution that would have the
side effect of having reusable parts while remaining concise and
easy to follow. 

I will take some great ideas from the previous algorithms, and
also add some concepts of my own ;-)

Here is what I came up with:


class Integer
  @@Ones=%w(one two three four five six seven eight nine).unshift('')
  @@Teens=%w(ten eleven twelve thirteen fourteen fifteen 
	sixteen seventeen eighteen nineteen)
  @@Tens=%w(twenty thirty forty fifty sixty seventy eighty ninety).unshift('','')
  @@Illions=%w(thousand million billion trillion quadrillion quintillion 
	sextillion septillion octillion nonillion decillion undecillion 
	duodecillion tredecillion quattuordecillion quindecillion sexdecillion 
	septendecillion octodecillion novemdecillion vigintillion).unshift('')

  def say_sign
    ["zero","","negative"][self<=>0]
  end
  def digit(n=-1)
    self.to_s[n..n].to_i
  end
  def say_ones
    return @@Teens[digit] if digit(-2)==1
    @@Ones[digit]
  end
  def say_tens
    @@Tens[digit(-2)]
  end
  def say_hundreds
    return "" if digit(-3)<1
    @@Ones[digit(-3)] + " hundred"
  end
  def say_triplet(triplet=0)
    words = say_hundreds + " " + say_tens
    words += "-" unless say_tens.empty? || say_ones.empty?
    words += say_ones 
    words += " " + @@Illions[triplet] unless self.zero?
    words.squeeze(" ").strip
  end
  def each_triplet
    s=self.to_s; triplets=[]
    triplets.unshift(s.slice!(/(.?.?.)$/)) until s.empty?
    triplets.each_with_index{|t,i| yield t,triplets.length-i-1 }
  end
  def say
    phrases=[say_sign]
    self.each_triplet{|t,i| phrases << t.to_i.say_triplet(i)}
    puts phrases.join(" ").squeeze(" ").strip
  end
  def commafy
    triplets=[]; sign=self.to_s.slice!(/^[-]/).to_s
    self.abs.each_triplet{|t,i| triplets << t }
    sign + triplets.join(",")
  end
end


0.say
-1234.say
1000004000001.say
-110000010000001.commafy
(54321-12345).say
(10**63+10**54+10**34).say

zero
negative one thousand two hundred thirty-four
one trillion four million one
"-110,000,010,000,001"
forty-one thousand nine hundred seventy-six
one vigintillion one septendecillion ten decillion


I ended up making an iterator, each_triplet, which returns
the triplets in the proper order along with an index signifying
its level:

1234567890 -> [["1",3],["234",2],["567",1],["890",0]]

I could have simplified the iterator at the expense of it
yielding triplets in reverse order:

  def reverse_each_triplet
    s=self.to_s; len=(s.length/3.0).ceil-1
    0.upto(len) {|i| yield s.slice!(/(.?.?.)$/), i }
  end

The other methods can also be used directly (hey, maybe someone
can use them for something?):

1234567890.say_triplet -> eight hundred ninety
1234567890.say_hundreds -> eight hundred
2352353514.digit(4) -> 3

The commafy method was easy using the each_triplet method,
although saving the possible minus sign makes it look messy.

possible errata...
One thing I noticed about the iterator I made, is that it was sending 
both parameters even if the block provided for only one. This happened
in the commafy block, which is why I use "|t,i|" even though I
only needed t for that. Yet the top of page 43 in the PR Book says that
any extra parameters passed by yield to a block are ignored (Dave?)


Guy N. Hurst


-- 
HurstLinks Web Development    http://www.hurstlinks.com/
Norfolk, VA - (757)623-9688
PHP/MySQL - Ruby/Perl - HTML/Javascript