Skip to content

Instantly share code, notes, and snippets.

@jlogsdon
Created May 18, 2011 20:19
Show Gist options
  • Save jlogsdon/979454 to your computer and use it in GitHub Desktop.
Save jlogsdon/979454 to your computer and use it in GitHub Desktop.
Converts a Double to Natural Language
class Convert
def self.to_string(double)
split = double.to_s.split('.')
# Tack the tens on to cents if not present (.90 => .9 for example)
split[1] << "0" if split[1] and split[1].length == 1
dollars = convert(split[0])
cents = convert(split[1])
dollars = plural(dollars, 'Dollar', split[0]) if dollars
cents = plural(cents, 'Cent', split[1]) if cents
return "Free" unless dollars or cents
return dollars unless cents
return cents unless dollars
return "#{dollars} and #{cents}"
end
private
def self.convert(digit)
return nil if !digit or digit == "0"
build = digitToWords(digit)
build = insertPlaceNames(build)
build = compileGroups(build)
build.join(', ').strip
end
def self.plural words, word, digit
word << "s" if digit.to_i > 1
"#{words} #{word}"
end
def self.insertPlaceNames(build)
build.map! do |group|
if group.select { |digit| !!digit }.length == 0
nil
else
group
end
end
build.each_index do |idx|
next unless build[idx]
# Handle the actual place name (for thousands and up)
build[idx] << "#{build[idx].pop} #{placeName(build.length - idx)}" unless (idx == build.length - 1)
# Handle the hundred spot for this group
build[idx].unshift "#{build[idx].shift} #{placeName(1)}" if build[idx].length == 3
end
build
end
def self.placeName(place)
return nil if place == 0
return "Hundred" if place == 1
return "Thousand" if place == 2
return "Million" if place == 3
return "Billion" if place == 4
return "Trillion" if place == 5
end
def self.compileGroups(build)
build.select { |g| !!g }.map do |group|
group = group.select { |w| w }
if group.length > 1
group << [group.pop, group.pop].reverse.join('-')
end
group.join(' and ')
end
end
def self.digitToWords(digit)
build = []
groups = (digit.length / 3.0).ceil - 1
groups.downto(0).each do |g|
words = []
group = digit.reverse[g * 3, 3].reverse
# Shortcircuit single digits
if group.length == 1
words << wordSingle(group)
build << words
next
end
# Handle the thousands
if group.length == 3
words << wordSingle(group[0,1])
group = group[1,2]
end
# Now we know we have a tens group left
if group.start_with? "1"
words << wordSingleTen(group)
else
words << wordTen(group[0,1])
words << wordSingle(group[1,1])
end
build << words
end
build
end
def self.wordSingle(digit)
return nil if digit == "0"
return "One" if digit == "1"
return "Two" if digit == "2"
return "Three" if digit == "3"
return "Four" if digit == "4"
return "Five" if digit == "5"
return "Six" if digit == "6"
return "Seven" if digit == "7"
return "Eight" if digit == "8"
return "Nine" if digit == "9"
end
def self.wordTen(digit)
return nil if digit == "0"
return "Ten" if digit == "1"
return "Twenty" if digit == "2"
return "Thirty" if digit == "3"
return "Fourty" if digit == "4"
return "Fifty" if digit == "5"
return "Sixty" if digit == "6"
return "Seventy" if digit == "7"
return "Eighty" if digit == "8"
return "Ninety" if digit == "9"
end
def self.wordSingleTen(digit)
return "Ten" if digit == "10"
return "Eleven" if digit == "11"
return "Twelve" if digit == "12"
return "Thirteen" if digit == "13"
return "Fourteen" if digit == "14"
return "Fifteen" if digit == "15"
return "Sixteen" if digit == "16"
return "Seventeen" if digit == "17"
return "Eighteen" if digit == "18"
return "Nineteen" if digit == "19"
end
end
require 'convert'
describe Convert do
describe "to_string" do
it "should convert doubles to word form" do
Convert.to_string(10000).should == "Ten Thousand Dollars"
Convert.to_string(0.01).should == "One Cent"
Convert.to_string(0.12).should == "Twelve Cents"
Convert.to_string(1.23).should == "One Dollar and Twenty-Three Cents"
Convert.to_string(12.34).should == "Twelve Dollars and Thirty-Four Cents"
Convert.to_string(123.45).should == "One Hundred and Twenty-Three Dollars and Fourty-Five Cents"
Convert.to_string(1234.56).should == "One Thousand, Two Hundred and Thirty-Four Dollars and Fifty-Six Cents"
Convert.to_string(12345.67).should == "Twelve Thousand, Three Hundred and Fourty-Five Dollars and Sixty-Seven Cents"
Convert.to_string(123456.78).should == "One Hundred and Twenty-Three Thousand, Four Hundred and Fifty-Six Dollars and Seventy-Eight Cents"
Convert.to_string(1234567.89).should == "One Million, Two Hundred and Thirty-Four Thousand, Five Hundred and Sixty-Seven Dollars and Eighty-Nine Cents"
Convert.to_string(12345678.90).should == "Twelve Million, Three Hundred and Fourty-Five Thousand, Six Hundred and Seventy-Eight Dollars and Ninety Cents"
Convert.to_string(999999999999.99).should == "Nine Hundred and Ninety-Nine Billion, Nine Hundred and Ninety-Nine Million, Nine Hundred and Ninety-Nine Thousand, Nine Hundred and Ninety-Nine Dollars and Ninety-Nine Cents"
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment