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