numbers_in_words 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/CHANGELOG DELETED
@@ -1 +0,0 @@
1
- v0.1.0. Handles decimals
data/Manifest DELETED
@@ -1,11 +0,0 @@
1
- CHANGELOG
2
- Manifest
3
- README
4
- Rakefile
5
- examples/display_numbers_in_words.rb
6
- init.rb
7
- lib/numbers.rb
8
- lib/numbers_in_words.rb
9
- lib/words.rb
10
- spec/numbers_in_words_spec.rb
11
- spec/words_in_numbers_spec.rb
data/README DELETED
@@ -1,84 +0,0 @@
1
- Installation
2
- ============
3
-
4
- gem install numbers_in_words
5
-
6
- or
7
-
8
- sudo gem install numbers_in_words
9
-
10
-
11
-
12
-
13
- The file numbers_to_words defines a module NumbersToWords which is included in Fixnum and Bignum.
14
- The in_words method can then be used on any Fixnum or Bignum object.
15
-
16
- E.g.
17
- >require 'numbers_in_words'
18
- >112.in_words
19
- => one hundred and twelve
20
- >"one googol".in_numbers
21
- =>10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
22
- >"Seventy million, five-hundred and fifty six thousand point eight nine three".in_numbers
23
- => 70556000.893
24
-
25
- ---------------
26
- Example program
27
-
28
- To try it out the program display_numbers_to_words.rb expects two integer parameters to define a
29
- range. It then prints out all numbers in words included in this range.
30
-
31
- e.g.
32
-
33
- >ruby display_numbers_to_words.rb 1 11
34
- one
35
- two
36
- three
37
- four
38
- five
39
- six
40
- seven
41
- eight
42
- nine
43
- ten
44
- eleven
45
-
46
- Whilst creating this project I realized that in English:
47
-
48
- * Numbers are grouped in groups of threes
49
- * Numbers less than 1,000 are grouped by hundreds and then by tens
50
- * There are specific rules for when we put an "and" in between numbers
51
-
52
- It makes sense to manage the numbers by these groups, so
53
- I created a method groups_of which will split any integer into
54
- groups of a certain size. It returns a hash with the power of ten
55
- as the key and the multiplier as the value. E.g:
56
-
57
- > 31245.groups_of(3)
58
- #=>
59
- {0=>245,3=>31} #i.e. 31 thousands, and 245 ones
60
-
61
- > 245.group_of(2)
62
- #=>
63
- {0=>45,2=>2} #i.e. 2 hundreds, and 45 ones
64
-
65
- I also created a method group_words takes a block and a size parameter
66
- This method which could be used by different languages.
67
- (In Japanese numbers are grouped in groups of 4, so it makes sense to try and
68
- separate the language related stuff from the number grouping related stuff)
69
-
70
- Example of usage:
71
- 245.group_words(2,"English") do |power, name, digits|
72
- puts "#{digits}*10^#{power} #{digits} #{name}s"
73
- end
74
-
75
- 2*10^2= 2 hundreds
76
- 45*10^0 = 45 ones
77
-
78
- Future plans
79
- ============
80
-
81
- * Handle complex numbers
82
- * Option for outputting punctuation
83
- * Reject invalid numbers
84
- * Support for other languages
@@ -1,22 +0,0 @@
1
- require 'rubygems'
2
- require 'numbers_in_words'
3
- def usage code=-1
4
- puts "\nUsage:\n\nruby #{__FILE__} <start> <end>"
5
- exit code
6
- end
7
- if ARGV.length != 2
8
-
9
- puts "Start and end arguments expected"
10
- usage -1
11
- end
12
- start_number = ARGV[0].to_i
13
- end_number = ARGV[1].to_i
14
-
15
- if start_number > end_number
16
- puts "Start number must be less than or equal to the end number"
17
- usage -2
18
- end
19
-
20
- for i in start_number..end_number do
21
- puts i.in_words
22
- end
data/init.rb DELETED
@@ -1,8 +0,0 @@
1
- require 'rubygems'
2
-
3
- $LOAD_PATH.unshift File.expand_path(File.join(File.dirname(__FILE__), 'lib'))
4
-
5
- require 'lib/numbers_in_words'
6
- require 'lib/words_in_numbers'
7
-
8
-
data/lib/numbers.rb DELETED
@@ -1,260 +0,0 @@
1
- require 'rubygems'
2
- require 'active_support/core_ext/array'
3
- module NumbersInWords
4
- EXCEPTIONS = {
5
- 10 => "ten",
6
- 11 => "eleven",
7
- 12 => "twelve",
8
-
9
- 13 => "thirteen",
10
- 14 => "fourteen",
11
- 15 => "fifteen",
12
- 16 => "sixteen" ,
13
- 17 => "seventeen",
14
- 18 => "eighteen",
15
- 19 => "nineteen",
16
-
17
- 20 => "twenty",
18
- 30 => "thirty",
19
- 40 => "forty",
20
- 50 => "fifty",
21
- 60 => "sixty",
22
- 70 => "seventy",
23
- 80 => "eighty",
24
- 90 => "ninety"
25
- }
26
-
27
- DIGITS = %w[zero one two three four five six seven eight nine]
28
-
29
- POWERS_OF_TEN ={
30
- 0 => "one",
31
- 1 => "ten",
32
- 2 => "hundred",
33
- 3 => "thousand",
34
- 6 => "million",
35
- 9 => "billion",
36
- 12 => "trillion",
37
- 15 => "quadrillion",
38
- 18 => "quintillion",
39
- 21 => "sextillion",
40
- 24 => "septillion",
41
- 27 => "octillion",
42
- 30 => "nonillion",
43
- 33 => "decillion",
44
- 36 => "undecillion",
45
- 39 => "duodecillion",
46
- 42 => "tredecillion",
47
- 45 => "quattuordecillion",
48
- 48 => "quindecillion",
49
- 51 => "sexdecillion",
50
- 54 => "septendecillion",
51
- 57 => "octodecillion",
52
- 60 => "novemdecillion",
53
- 63 => "vigintillion",
54
- 66 => "unvigintillion",
55
- 69 => "duovigintillion",
56
- 72 => "trevigintillion",
57
- 75 => "quattuorvigintillion",
58
- 78 => "quinvigintillion",
59
- 81 => "sexvigintillion",
60
- 84 => "septenvigintillion",
61
- 87 => "octovigintillion",
62
- 90 => "novemvigintillion",
63
- 93 => "trigintillion",
64
- 96 => "untrigintillion",
65
- 99 => "duotrigintillion",
66
- 100 => "googol"
67
- }
68
-
69
- LENGTH_OF_GOOGOL = 101 #length of the string i.e. one with 100 zeros
70
-
71
- def in_words language="English"
72
- case language
73
- when "English" #allow for I18n
74
- in_english
75
- end
76
- end
77
-
78
- def in_english
79
- #handle 0-9
80
- return DIGITS[self] if self.is_a?(Integer) and (0..9).to_a.include? self
81
- #teens etc
82
- return EXCEPTIONS[self] if self.is_a?(Integer) and EXCEPTIONS[self]
83
-
84
- writer = LanguageWriterEnglish.new(self)
85
-
86
- in_decimals = writer.decimals
87
- return in_decimals unless in_decimals.nil?
88
-
89
- number = to_i
90
-
91
- return writer.negative() if number < 0
92
-
93
- length = number.to_s.length
94
- output = ""
95
-
96
- if length == 2 #20-99
97
- tens = (number/10).round*10 #write the tens
98
-
99
- output << EXCEPTIONS[tens] # e.g. eighty
100
-
101
- digit = number - tens #write the digits
102
-
103
- output << " " + digit.in_english unless digit==0
104
- else
105
- output << writer.write() #longer numbers
106
- end
107
-
108
- output.strip
109
- end
110
-
111
- protected
112
-
113
- class LanguageWriter
114
- attr_accessor :number
115
-
116
- def initialize number
117
- @number = number
118
- end
119
-
120
- def group_words size
121
- #1000 and over Numbers are split into groups of three
122
- groups = NumberGroup.groups_of @number, size
123
- powers = groups.keys.sort.reverse #put in descending order
124
-
125
- powers.each do |power|
126
- name = POWERS_OF_TEN[power]
127
- digits = groups[power]
128
- yield power, name, digits
129
- end
130
- end
131
- end
132
-
133
- class LanguageWriterEnglish < LanguageWriter
134
- def negative
135
- "minus " + (-@number).in_english
136
- end
137
-
138
- def write
139
- length = @number.to_s.length
140
- output = if length == 3
141
- #e.g. 113 splits into "one hundred" and "thirteen"
142
- write_groups(2)
143
-
144
- #more than one hundred less than one googol
145
- elsif length < LENGTH_OF_GOOGOL
146
- write_groups(3)
147
-
148
- elsif length >= LENGTH_OF_GOOGOL
149
- write_googols
150
-
151
- end
152
- output.strip
153
- end
154
-
155
- def decimals
156
- int, decimals = NumberGroup.new(@number).split_decimals
157
- if int
158
- out = int.in_english + " point "
159
- decimals.each do |decimal|
160
- out << decimal.to_i.in_english + " "
161
- end
162
- out.strip
163
- end
164
- end
165
-
166
- private
167
- def write_googols
168
- googols, remainder = NumberGroup.new(@number).split_googols
169
- output = ""
170
- output << " " + googols.in_words + " googol"
171
- if remainder > 0
172
- prefix = " "
173
- prefix << "and " if remainder < 100
174
- output << prefix + remainder.in_english
175
- end
176
- output
177
- end
178
-
179
- def write_groups group
180
- #e.g. 113 splits into "one hundred" and "thirteen"
181
- output = ""
182
- group_words(group) do |power, name, digits|
183
- if digits > 0
184
- prefix = " "
185
- #no and between thousands and hundreds
186
- prefix << "and " if power == 0 and digits < 100
187
- output << prefix + digits.in_english
188
- output << prefix + name unless power == 0
189
- end
190
- end
191
- output
192
- end
193
- end
194
-
195
- class NumberGroup
196
- include Enumerable
197
- attr_accessor :number
198
-
199
- def each
200
- @array.each { |item| yield item}
201
- end
202
-
203
- #split into groups this gives us 1234567 => 123 456 7
204
- #so we need to reverse first
205
- #in stages
206
- def initialize number
207
- @number = number
208
- end
209
-
210
- def groups size
211
- #i.e. 1234567 => 7654321
212
- groups = @number.to_s.reverse
213
- #7654321 => 765 432 1
214
- @array = groups.split("").in_groups_of(size)
215
- #765 432 1 => 1 432 765
216
- @array.reverse!
217
- #1 432 765 => 1 234 567
218
- #and turn back into integers
219
- @array.map! {|group| group.reverse.join("").to_i}
220
- @array.reverse! # put in ascending order of power of ten
221
- power = 0
222
- output = @array.inject({}) do |output, digits|
223
- output[power] = digits
224
- power += size
225
- output
226
- end
227
- output
228
- end
229
-
230
- def split_decimals
231
- if @number.is_a? Float
232
- int = @number.to_i
233
- decimal = @number - int
234
- decimal = decimal.to_s.split(".")[1]
235
- digits = decimal.split //
236
- #convert to integers array
237
- digits.inject([]) {|out, digit|
238
- out<< digit.to_i
239
- }
240
- return int, digits
241
- end
242
- end
243
-
244
- def self.groups_of number, size
245
- new(number).groups(size)
246
- end
247
-
248
- def split_googols
249
- output = ""
250
- googols = @number.to_s[0 .. (-LENGTH_OF_GOOGOL)].to_i
251
- remainder = @number.to_s[(1-LENGTH_OF_GOOGOL) .. -1].to_i
252
- return googols, remainder
253
- end
254
- end
255
- end
256
-
257
-
258
- class Numeric
259
- include NumbersInWords
260
- end
data/lib/words.rb DELETED
@@ -1,221 +0,0 @@
1
- module WordsInNumbers
2
- def in_numbers
3
- text = to_s
4
-
5
- WordToNumber.new.instance_eval do
6
- text = strip_punctuation text
7
- #negative numbers
8
- return -1 * (text.gsub(/^minus /, "")).in_numbers if text =~ /^minus /
9
-
10
- #easy single word case
11
- word = word_to_integer(text)
12
- return word unless word.nil?
13
-
14
- #decimals
15
- match = text.match(/\spoint\s/)
16
- if match
17
- integer = match.pre_match.in_numbers
18
-
19
- decimal = decimal_portion match.post_match
20
-
21
- return integer + decimal
22
- end
23
-
24
- #multiple word case
25
- words = text.split " "
26
- integers = word_array_to_integers words
27
-
28
- integer= parse_numbers(integers)
29
- return integer unless integer.nil?
30
- return nil
31
- end
32
- end
33
-
34
- class WordToNumber
35
- DIGITS= %w[zero one two three four five six seven eight nine]
36
-
37
- EXCEPTIONS = {
38
- "ten" => 10,
39
- "eleven" => 11,
40
- "twelve" => 12,
41
- "thirteen" => 13,
42
- "fourteen" => 14,
43
- "fifteen" => 15,
44
- "sixteen" => 16,
45
- "seventeen" => 17,
46
- "eighteen" => 18,
47
- "nineteen" => 19,
48
- "twenty" => 20,
49
- "thirty" => 30,
50
- "forty" => 40,
51
- "fifty" => 50,
52
- "sixty" => 60,
53
- "seventy" => 70,
54
- "eighty" => 80,
55
- "ninety" => 90
56
- }
57
-
58
-
59
- POWERS_OF_TEN ={
60
- "one" => 0,
61
- "ten" => 1 ,
62
- "hundred" => 2,
63
- "thousand" => 3 ,
64
- "million" => 6,
65
- "billion" => 9,
66
- "trillion" => 12,
67
- "quadrillion" => 15,
68
- "quintillion" => 18,
69
- "sextillion" => 21,
70
- "septillion" => 24,
71
- "octillion" => 27,
72
- "nonillion" => 30,
73
- "decillion" => 33,
74
- "undecillion" => 36,
75
- "duodecillion" => 39,
76
- "tredecillion" => 42,
77
- "quattuordecillion" => 45,
78
- "quindecillion" => 48,
79
- "sexdecillion" => 51,
80
- "septendecillion" => 54,
81
- "octodecillion" => 57,
82
- "novemdecillion" => 60,
83
- "vigintillion" => 63,
84
- "unvigintillion" => 66,
85
- "duovigintillion" => 69,
86
- "trevigintillion" => 72,
87
- "quattuorvigintillion" => 75,
88
- "quinvigintillion" => 78,
89
- "sexvigintillion" => 81,
90
- "septenvigintillion" => 84,
91
- "octovigintillion" => 87,
92
- "novemvigintillion" => 90,
93
- "trigintillion" => 93,
94
- "untrigintillion" => 96,
95
- "duotrigintillion" => 99,
96
- "googol" => 100
97
- }
98
-
99
- def strip_punctuation text
100
- text = text.downcase.gsub /[^a-z ]/, " "
101
- to_remove = true
102
-
103
- to_remove = text.gsub! " ", " " while to_remove
104
-
105
- text
106
- end
107
-
108
- def decimal_portion text
109
- words = text.split " "
110
- integers = word_array_to_integers words
111
- decimal = "0." + integers.join()
112
- decimal.to_f
113
- end
114
-
115
-
116
- private
117
-
118
- # Example: 364,895,457,898
119
- #three hundred and sixty four billion eight hundred and ninety five million
120
- #four hundred and fifty seven thousand eight hundred and ninety eight
121
- #
122
- #3 100 60 4 10^9, 8 100 90 5 10^6, 4 100 50 7 1000, 8 100 90 8
123
- # memory answer
124
- #x1. 3 add to memory because answer and memory are zero 3 0
125
- #x2. memory * 100 (because memory<100) 300 0
126
- #x3. 60 add to memory because memory > 60 360 0
127
- #x3. 4 add to memory because memory > 4 364 0
128
- #x4. multiply memory by 10^9 because memory < power of ten 364*10^9 0
129
- #x5. add memory to answer (and reset)memory > 8 (memory pow of ten > 2) 0 364*10^9
130
- #x6. 8 add to memory because not finished 8 ''
131
- #x7. multiply memory by 100 because memory < 100 800 ''
132
- #x8. add 90 to memory because memory > 90 890 ''
133
- #x9. add 5 to memory because memory > 5 895 ''
134
- #x10. multiply memory by 10^6 because memory < power of ten 895*10^6 ''
135
- #x11. add memory to answer (and reset) because memory power ten > 2 0 364895 * 10^6
136
- #x12. 4 add to memory because not finished 4 ''
137
- #x13. memory * 100 because memory < 100 400 ''
138
- #x14. memory + 50 because memory > 50 450 ''
139
- #x15. memory + 7 because memory > 7 457 ''
140
- #x16. memory * 1000 because memory < 1000 457000 ''
141
- #x17. add memory to answer (and reset)memory > 8 (memory pow of ten > 2) 0 364895457000
142
- #x18. 8 add to memory because not finished 8 ''
143
- #x19. memory * 100 because memory < 100 800 ''
144
- #x14. memory + 90 because memory > 90 890 ''
145
- #x15. memory + 8 because memory > 8 898 ''
146
- #16. finished so add memory to answer
147
-
148
- #Example
149
- #2001
150
- #two thousand and one
151
- #2 1000 1
152
- # memory answer
153
- #1. add 2 to memory because first 2 0
154
- #2. multiply memory by 1000 because memory < 1000 2000 0
155
- #3. add memory to answer,reset, because power of ten>2 0 2000
156
- #4. add 1 to memory 1 2000
157
- #5. finish - add memory to answer 0 2001
158
- def parse_numbers(integers)
159
- memory = 0
160
- answer = 0
161
- reset = true #reset each time memory is reset
162
- integers.each_with_index do |integer, index|
163
- if reset
164
- reset = false
165
- memory += integer
166
- else
167
- #x4. multiply memory by 10^9 because memory < power of ten
168
- if is_power_of_ten?(integer)
169
- if power_of_ten(integer)> 2
170
- memory *= integer
171
- #17. add memory to answer (and reset) (memory pow of ten > 2)
172
- answer += memory
173
- memory = 0
174
- reset = true
175
- end
176
- end
177
-
178
- if memory < integer
179
- memory *= integer
180
- else
181
- memory += integer
182
- end
183
- end
184
- end
185
- answer += memory
186
- end
187
-
188
- def power_of_ten integer
189
- Math.log10(integer)
190
- end
191
-
192
- def is_power_of_ten? integer
193
- power_of_ten(integer)==power_of_ten(integer).to_i
194
- end
195
-
196
- #handles simple single word numbers
197
- #e.g. one, seven, twenty, eight, thousand etc
198
- def word_to_integer word
199
- text = word.to_s.chomp.strip
200
- #digits 0-9
201
- digit = DIGITS.index(text)
202
- return digit unless digit.nil?
203
-
204
- #digits which are exceptions
205
- exception = EXCEPTIONS[text]
206
- return exception unless exception.nil?
207
-
208
- power = POWERS_OF_TEN[text]
209
- return 10**power unless power.nil?
210
- end
211
-
212
- def word_array_to_integers words
213
- words.map { |i| word_to_integer i }.compact
214
- end
215
- end
216
- end
217
-
218
- class String
219
- include WordsInNumbers
220
- end
221
-