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.
If you don't want to use any Gem then....
Try this one(this will convert upto million):
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"
Related
Is there a simple Rails/Ruby helper function to help you convert human readable numbers to actual numbers?
Such as:
1K => 1000
2M => 2,000,000
2.2K => 2200
1,500 => 1500
50 => 50
5.5M => 5500000
test = {
'1K' => 1000,
'2M' => 2000000,
'2.2K' => 2200,
'1,500' => 1500,
'50' => 50,
'5.5M' => 5500000
}
class String
def human_readable_to_i
multiplier = {'K' => 1_000, 'M' => 1_000_000}[self.upcase[/[KM](?=\z)/]] || 1
value = self.gsub(/[^\d.]/, '')
case value.count('.')
when 0 then value.to_i
when 1 then value.to_f
else 0
end * multiplier
end
end
test.each { |k, v| raise "Test failed" unless k.human_readable_to_i == v }
Try something like this if you have an array of human readable numbers than
array.map do |elem|
elem = elem.gsub('$','')
if elem.include? 'B'
elem.to_f * 1000000000
elsif elem.include? 'M'
elem.to_f * 1000000
elsif elem.include? 'K'
elem.to_f * 1000
else
elem.to_f
end
end
Have a look here as well, you will find many Numbers Helpers
NumberHelper Rails.
Ruby Array human readable to actual
I am looking to display a html tree from nested set data.
As the displayed tree does not always display all branches the leaf nodes cannot be identified by subtracting the lft & rgt values.
1 Drinks 27
/ | \
2 Coffee 3 4 Tea 20 21 Milk 26
/ \
5 Black 8 9 Green 19
/ \
10 China 14 15 Africa 18
I was looking to adapt the following code:
How to render all records from a nested set into a real html tree
Solution:
Happy to receive code improvement suggestions :)
def tree_from_set(set, start_level)
buf = "<ul>"
parent = []
prev = set[start_level]
set[start_level+1..-1].each do |node|
if node.lft.between?(prev.lft, prev.rgt)
# Previous was the parent
buf << open_parent_tag(prev)
parent.push(prev)
else
if node.lft.between?(parent.last.lft, parent.last.rgt)
#Previous was a child
buf << leaf_tag(prev)
else
buf << leaf_tag(prev)
begin
buf << "</ul></li>"
parent.pop
end until parent.empty? or node.lft.between?(parent.last.lft, parent.last.rgt)
end
end
prev = node
end
buf << leaf_tag(prev)
begin
buf << "</ul></li>"
parent.pop
end until parent.empty?
buf << "</ul>"
buf.html_safe
end
def open_parent_tag(node)
%{ <li>
#{link_to(node.name, node)}
<ul>
}
end
def leaf_tag(node)
content_tag(:li, link_to(node.name, node))
end
I used this function, but on php, not on ruby:
<?php
//nested sets data ordered by left
$data = array(
array("left" => 1, "right" => 10, "name" => "P0"),
array("left" => 2, "right" => 7, "name" => "P1"),
array("left" => 3, "right" => 4, "name" => "P11"),
array("left" => 5, "right" => 6, "name" => "P12"),
array("left" => 8, "right" => 9, "name" => "P2")
);
//Converter function gets nested sets array and returns nested php array
function nest($arrData){
$stack = array();
$arraySet = array();
foreach( $arrData as $intKey=>$arrValues) {
$stackSize = count($stack);
while($stackSize > 0 && $stack[$stackSize-1]['right'] < $arrValues['left']) {
array_pop($stack);
$stackSize--;
}
$link =& $arraySet;
for($i=0;$i<$stackSize;$i++) {
$link =& $link[$stack[$i]['id']]["children"]; //navigate to the proper children array
}
$tmp = array_push($link, array ('item'=>$arrValues,'children'=>array()));
array_push($stack, array('id' => $tmp-1, 'right' => $arrValues['right']));
}
return $arraySet;
}
//Print result
printArray(nest($data));
function printArray($array){
echo "<ul>";
foreach ($array as $row){
$children = $row['children'];
echo "<li>";
echo $row['item']['name'];
if (!empty($children)) printArray($children);
echo "</li>";
}
echo "</ul>";
}
?>
Managed to convert it to C++ for those who was looking for it like I was.
readDataBaseData(QVector<NodeData> &data, DBNode *node)
{
if(data.size() < 1){
return;
}
QVector<QPair<NodeData, int>> stack;
DBNode* arrayRes = node;
foreach (NodeData curArrDataItem, data) {
int stackSize = stack.size();
while(stackSize > 0 &&
stack.at(stackSize - 1).first.right < curArrDataItem.left){
stack.pop_back();
stackSize--;
}
DBNode* link = arrayRes;
for(int i = 0; i < stackSize; i++){
link = link->childAt(stack.at(i).second);
}
link = new DBNode(curArrDataItem, link);
stack.push_back(QPair<NodeData, int>(curArrDataItem, link->getParent()->childCount() - 1));
}
}
Rails 4.0.2
I can't make work pluralization properly. Only :zero, :one and :other works. But I need all of forms: :zero, :one, :few, :many, :other.
In the config/initializers folder file pluralization.rb has been created:
Variant 1:
require "i18n/backend/pluralization"
I18n::Backend::Simple.send(:include, I18n::Backend::Pluralization)
{
:ru => { :i18n => { :plural => { :keys => [:one, :few, :many, :other], :rule => lambda { |n| n % 10 == 1 && n % 100 != 11 ? :one : [2, 3, 4].include?(n % 10) && ![12, 13, 14].include?(n % 100) ? :few : n % 10 == 0 || [5, 6, 7, 8, 9].include?(n % 10) || [11, 12, 13, 14].include?(n % 100) ? :many : :other } } } }
}
Variant 2:
require "i18n/backend/pluralization"
I18n::Backend::Simple.send(:include, I18n::Backend::Pluralization)
In the config/locales file ru.yml has been created:
ru:
kids:
zero: ru_zero
one: ru_one
few: ru_few
many: ru_many
other: ru_other
In application.rb:
config.i18n.default_locale = :ru
Test code:
0.upto 15 {|i|
i.to_s + " "
t(:kids, count: i)
}
Output:
0 ru_zero
1 ru_one
2 ru_other
3 ru_other
4 ru_other
5 ru_other
6 ru_other
7 ru_other
8 ru_other
9 ru_other
10 ru_other
11 ru_other
12 ru_other
13 ru_other
14 ru_other
15 ru_other
I confused.
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)
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"
Have you considered humanize ?
https://github.com/radar/humanize
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
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.
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/
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
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
Its been quite a while since the question was asked. Rails has something inbuilt for this now.
https://api.rubyonrails.org/classes/ActionView/Helpers/NumberHelper.html
number_to_human(1234567) # => "1.23 Million"
number_to_human(1234567890) # => "1.23 Billion"
number_to_human(1234567890123) # => "1.23 Trillion"
number_to_human(1234567890123456) # => "1.23 Quadrillion"
number_to_human(1234567890123456789) # => "1230 Quadrillion"
Anybody knows the method to convert the numericals to english number words in rails?
I found some Ruby scripts to convert numbericals to english words for corresponding words.
Instead of writing a script in ruby, i feel that direct function is available.
Eg. 1 -> One, 2 -> Two.
Use the numbers_and_words gem, https://github.com/kslazarev/numbers_and_words
The humanize gem that does exactly what you want:
require 'humanize'
23.humanize # => "twenty three"
0.42.humanize(decimals_as: :digits) # => "zero point four two"
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/
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.
How about this? Written for converting numbers to words in the Indian system, but can be easily modified.
def to_words(num)
numbers_to_name = {
10000000 => "crore",
100000 => "lakh",
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"
}
log_floors_to_ten_powers = {
0 => 1,
1 => 10,
2 => 100,
3 => 1000,
4 => 1000,
5 => 100000,
6 => 100000,
7 => 10000000
}
num = num.to_i
return '' if num <= 0 or num >= 100000000
log_floor = Math.log(num, 10).floor
ten_power = log_floors_to_ten_powers[log_floor]
if num <= 20
numbers_to_name[num]
elsif log_floor == 1
rem = num % 10
[ numbers_to_name[num - rem], to_words(rem) ].join(' ')
else
[ to_words(num / ten_power), numbers_to_name[ten_power], to_words(num % ten_power) ].join(' ')
end
end
You may also want to check gem 'rupees' - https://github.com/railsfactory-shiv/rupees to convert numbers to indian rupees (e.g. in Lakh, Crore, etc)