/
phrases.rb
178 lines (148 loc) · 4.38 KB
/
phrases.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
require 'pry'
require 'ruby_rhymes'
class Phrases
attr_accessor :all_sentences, :start_phrases, :mid_phrases, :end_phrases, :text
ONES = %w(zero one two three four five six seven eight nine)
TENS = %w(zero ten twenty thirty forty fifty sixty seventy eighty ninety)
TEENS = {'ten one' => 'eleven',
'ten two' => 'twelve',
'ten three' => 'thirteen',
'ten four' => 'fourteen',
'ten five' => 'fifteen',
'ten six' => 'sixteen',
'ten seven' => 'seventeen',
'ten eight' => 'eighteen',
'ten nine' => 'nineteen'}
MULTISYLLABLES = %w(ia io[^n] ua oi ed\z nuclear eo [^aeiou]le\z)
def initialize(text)
self.text = get_clean_text(text)
self.all_sentences = get_all_sentences
end
def get_clean_text(text)
if text =~ /\.(txt|md)\z/
File.open(text, 'r').each.inject('') do |string, line|
string.concat(line)
end
else
text
end.gsub(/(\n|["])/, '')
end
def get_all_sentences
sentences = text.scan(/[\A\.]\s+[^\.]+\./)
end
def get_syllable_count(word)
count = 0
return 0 if word =~ /\A([?!\-—–'";:$%]|--|——)\z/
return get_acronym_syllable_count(word) if is_acronym?(word)
begin
count = make_english_word(word).to_phrase.syllables
rescue
puts "Error thrown with word: #{word}"
end
count += 2 if word =~ /[%$]/
count
end
def get_phrase_syllables(string)
string.split.inject(0) do |sum, word|
sum += get_syllable_count(word)
end
end
def make_english_word(word)
return word unless word =~ /\d+/
word = word.gsub(/,/, '')
word = word.gsub(/(\d+)/) { decimal_to_word($1) }
end
def get_phrase(phase, num_syllables)
case phase
when "start"
loop do
phrase = start_phrases.sample
return phrase if get_phrase_syllables(phrase) == num_syllables
end
when "mid"
loop do
phrase = mid_phrases.sample
return phrase if get_phrase_syllables(phrase) == num_syllables
end
when "end"
loop do
phrase = end_phrases.sample
return phrase if get_phrase_syllables(phrase) == num_syllables
end
end
end
def get_sentence(num_syllables)
loop do
sentence = all_sentences.sample
return sentence if get_phrase_syllables(sentence) == num_syllables
end
end
def decimal_to_word(word)
# handles decimal numbers 0 to 999999
word = word.scan(/\d+/)[0]
decimal = word.to_s.chars.reverse
word_arr = []
decimal.each_with_index do |digit, index|
if index % 3 == 0
word_arr.push(ONES[digit.to_i])
elsif index % 3 == 1
word_arr.push(TENS[digit.to_i])
elsif index % 3 == 2
word_arr.push(ONES[digit.to_i] + ' hundred')
end
end
word_arr.reverse!
if decimal.count === 6
count = 2
loop do
current = word_arr[count]
if current != 'zero'
word_arr.insert(count + 1, 'thousand')
break
end
count = count - 1
end
elsif decimal.count > 3
insert_idx = decimal.count % 3
word_arr = word_arr.insert(insert_idx, 'thousand')
end
word_arr.delete_if { |word| word =~ /zero/ } unless word_arr.length == 1
word_str = word_arr.join(' ')
TEENS.each do |k, v|
word_str.gsub!(/#{k}/, v)
end
word_str
end
def is_acronym?(word)
(word =~ /(\A([A-Z]\.){2,}+\z|\A([A-Z]){2,}+\z)/) ? true : false
end
def get_acronym_syllable_count(word)
count = 0
count += word =~ /\./ ? word.length / 2 : word.length
return word =~ /w/i ? count + 1 : count
end
def get_splittable_text(syllable_pattern, sentence_lengths)
loop do
full_text = sentence_lengths.reduce('') do |aggregate, length|
aggregate.concat(get_sentence(length))
end
return full_text if match_syllable_pattern?(full_text, syllable_pattern)
end
end
def match_syllable_pattern?(text, pattern)
total_lengths = []
pattern.each_with_index do |length, i|
total_lengths[i] = pattern[0..i].reduce(:+)
end
total_lengths = total_lengths.select do |length|
length != 0
end
match_count = 0
text.split.reduce('') do |aggregate, word|
aggregate.concat(' ' + word)
match_count += 1 if total_lengths.include?(get_syllable_count(aggregate))
aggregate
end
match_count == total_lengths.length
end
end