summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKelly Rauchenberger <fefferburbia@gmail.com>2016-04-17 13:44:37 -0400
committerKelly Rauchenberger <fefferburbia@gmail.com>2016-04-17 13:44:37 -0400
commit04338f2b040fee5142904c062e0e38c836601034 (patch)
treea3ca42f738839ae4f6c83d599277c33203beb733
parent040ee58fecdc9c478004bc2e554e1ae126ec4602 (diff)
downloadverbly-04338f2b040fee5142904c062e0e38c836601034.tar.gz
verbly-04338f2b040fee5142904c062e0e38c836601034.tar.bz2
verbly-04338f2b040fee5142904c062e0e38c836601034.zip
Fixed perfect rhyming
Rhyme detection now ensures that any rhymes it finds are perfect rhymes and not identical rhymes. Rhyme detection is also now a lot faster because additional information is stored in the datafile.

Also fixed a bug in the query interface (and the generator) that could cause incorrect queries to be executed.
-rw-r--r--generator/generator.cpp128
-rw-r--r--generator/schema.sql8
-rw-r--r--lib/adjective_query.cpp68
-rw-r--r--lib/adjective_query.h10
-rw-r--r--lib/adverb_query.cpp68
-rw-r--r--lib/adverb_query.h10
-rw-r--r--lib/data.cpp2
-rw-r--r--lib/frame_query.cpp2
-rw-r--r--lib/noun_query.cpp73
-rw-r--r--lib/noun_query.h10
-rw-r--r--lib/preposition.cpp2
-rw-r--r--lib/verb_query.cpp68
-rw-r--r--lib/verb_query.h10
-rw-r--r--lib/word.cpp41
-rw-r--r--lib/word.h17
15 files changed, 442 insertions, 75 deletions
diff --git a/generator/generator.cpp b/generator/generator.cpp index e67bda7..e2ebfa1 100644 --- a/generator/generator.cpp +++ b/generator/generator.cpp
@@ -76,13 +76,24 @@ struct group_t {
76 std::list<std::list<framepart_t>> frames; 76 std::list<std::list<framepart_t>> frames;
77}; 77};
78 78
79struct pronunciation_t {
80 std::string phonemes;
81 std::string prerhyme;
82 std::string rhyme;
83
84 bool operator<(const pronunciation_t& other) const
85 {
86 return phonemes < other.phonemes;
87 }
88};
89
79std::map<std::string, group_t> groups; 90std::map<std::string, group_t> groups;
80std::map<std::string, verb_t> verbs; 91std::map<std::string, verb_t> verbs;
81std::map<std::string, adjective_t> adjectives; 92std::map<std::string, adjective_t> adjectives;
82std::map<std::string, noun_t> nouns; 93std::map<std::string, noun_t> nouns;
83std::map<int, std::map<int, int>> wn; 94std::map<int, std::map<int, int>> wn;
84std::map<int, int> images; 95std::map<int, int> images;
85std::map<std::string, std::set<std::string>> pronunciations; 96std::map<std::string, std::set<pronunciation_t>> pronunciations;
86 97
87void print_usage() 98void print_usage()
88{ 99{
@@ -590,7 +601,47 @@ int main(int argc, char** argv)
590 std::string canonical(phoneme_data[1]); 601 std::string canonical(phoneme_data[1]);
591 std::transform(std::begin(canonical), std::end(canonical), std::begin(canonical), ::tolower); 602 std::transform(std::begin(canonical), std::end(canonical), std::begin(canonical), ::tolower);
592 603
593 pronunciations[canonical].insert(phoneme_data[2]); 604 std::string phonemes = phoneme_data[2];
605 auto phoneme_set = verbly::split<std::list<std::string>>(phonemes, " ");
606 auto phemstrt = std::find_if(std::begin(phoneme_set), std::end(phoneme_set), [] (std::string phoneme) {
607 return phoneme.find("1") != std::string::npos;
608 });
609
610 pronunciation_t p;
611 p.phonemes = phonemes;
612 if (phemstrt != std::end(phoneme_set))
613 {
614 std::stringstream rhymer;
615 for (auto it = phemstrt; it != std::end(phoneme_set); it++)
616 {
617 std::string naked;
618 std::remove_copy_if(std::begin(*it), std::end(*it), std::back_inserter(naked), [] (char ch) {
619 return isdigit(ch);
620 });
621
622 if (it != phemstrt)
623 {
624 rhymer << " ";
625 }
626
627 rhymer << naked;
628 }
629
630 p.rhyme = rhymer.str();
631
632 if (phemstrt != std::begin(phoneme_set))
633 {
634 phemstrt--;
635 p.prerhyme = *phemstrt;
636 } else {
637 p.prerhyme = "";
638 }
639 } else {
640 p.prerhyme = "";
641 p.rhyme = "";
642 }
643
644 pronunciations[canonical].insert(p);
594 } 645 }
595 } 646 }
596 647
@@ -720,7 +771,7 @@ int main(int argc, char** argv)
720 db_error(ppdb, query); 771 db_error(ppdb, query);
721 } 772 }
722 773
723 sqlite3_bind_text(ppstmt, 1, prep.c_str(), prep.length(), SQLITE_STATIC); 774 sqlite3_bind_text(ppstmt, 1, prep.c_str(), prep.length(), SQLITE_TRANSIENT);
724 775
725 if (sqlite3_step(ppstmt) != SQLITE_DONE) 776 if (sqlite3_step(ppstmt) != SQLITE_DONE)
726 { 777 {
@@ -752,7 +803,7 @@ int main(int argc, char** argv)
752 } 803 }
753 804
754 sqlite3_bind_int(ppstmt, 1, rowid); 805 sqlite3_bind_int(ppstmt, 1, rowid);
755 sqlite3_bind_text(ppstmt, 2, group.c_str(), group.length(), SQLITE_STATIC); 806 sqlite3_bind_text(ppstmt, 2, group.c_str(), group.length(), SQLITE_TRANSIENT);
756 807
757 if (sqlite3_step(ppstmt) != SQLITE_DONE) 808 if (sqlite3_step(ppstmt) != SQLITE_DONE)
758 { 809 {
@@ -775,11 +826,11 @@ int main(int argc, char** argv)
775 db_error(ppdb, query); 826 db_error(ppdb, query);
776 } 827 }
777 828
778 sqlite3_bind_text(ppstmt, 1, mapping.second.infinitive.c_str(), mapping.second.infinitive.length(), SQLITE_STATIC); 829 sqlite3_bind_text(ppstmt, 1, mapping.second.infinitive.c_str(), mapping.second.infinitive.length(), SQLITE_TRANSIENT);
779 sqlite3_bind_text(ppstmt, 2, mapping.second.past_tense.c_str(), mapping.second.past_tense.length(), SQLITE_STATIC); 830 sqlite3_bind_text(ppstmt, 2, mapping.second.past_tense.c_str(), mapping.second.past_tense.length(), SQLITE_TRANSIENT);
780 sqlite3_bind_text(ppstmt, 3, mapping.second.past_participle.c_str(), mapping.second.past_participle.length(), SQLITE_STATIC); 831 sqlite3_bind_text(ppstmt, 3, mapping.second.past_participle.c_str(), mapping.second.past_participle.length(), SQLITE_TRANSIENT);
781 sqlite3_bind_text(ppstmt, 4, mapping.second.ing_form.c_str(), mapping.second.ing_form.length(), SQLITE_STATIC); 832 sqlite3_bind_text(ppstmt, 4, mapping.second.ing_form.c_str(), mapping.second.ing_form.length(), SQLITE_TRANSIENT);
782 sqlite3_bind_text(ppstmt, 5, mapping.second.s_form.c_str(), mapping.second.s_form.length(), SQLITE_STATIC); 833 sqlite3_bind_text(ppstmt, 5, mapping.second.s_form.c_str(), mapping.second.s_form.length(), SQLITE_TRANSIENT);
783 834
784 if (sqlite3_step(ppstmt) != SQLITE_DONE) 835 if (sqlite3_step(ppstmt) != SQLITE_DONE)
785 { 836 {
@@ -811,14 +862,26 @@ int main(int argc, char** argv)
811 862
812 for (auto pronunciation : pronunciations[canonical]) 863 for (auto pronunciation : pronunciations[canonical])
813 { 864 {
814 query = "INSERT INTO verb_pronunciations (verb_id, pronunciation) VALUES (?, ?)"; 865 if (!pronunciation.rhyme.empty())
866 {
867 query = "INSERT INTO verb_pronunciations (verb_id, pronunciation, prerhyme, rhyme) VALUES (?, ?, ?, ?)";
868 } else {
869 query = "INSERT INTO verb_pronunciations (verb_id, pronunciation) VALUES (?, ?)";
870 }
871
815 if (sqlite3_prepare_v2(ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK) 872 if (sqlite3_prepare_v2(ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK)
816 { 873 {
817 db_error(ppdb, query); 874 db_error(ppdb, query);
818 } 875 }
819 876
820 sqlite3_bind_int(ppstmt, 1, rowid); 877 sqlite3_bind_int(ppstmt, 1, rowid);
821 sqlite3_bind_text(ppstmt, 2, pronunciation.c_str(), pronunciation.length(), SQLITE_STATIC); 878 sqlite3_bind_text(ppstmt, 2, pronunciation.phonemes.c_str(), pronunciation.phonemes.length(), SQLITE_TRANSIENT);
879
880 if (!pronunciation.rhyme.empty())
881 {
882 sqlite3_bind_text(ppstmt, 3, pronunciation.prerhyme.c_str(), pronunciation.prerhyme.length(), SQLITE_TRANSIENT);
883 sqlite3_bind_text(ppstmt, 4, pronunciation.rhyme.c_str(), pronunciation.rhyme.length(), SQLITE_TRANSIENT);
884 }
822 885
823 if (sqlite3_step(ppstmt) != SQLITE_DONE) 886 if (sqlite3_step(ppstmt) != SQLITE_DONE)
824 { 887 {
@@ -856,7 +919,7 @@ int main(int argc, char** argv)
856 db_error(ppdb, query); 919 db_error(ppdb, query);
857 } 920 }
858 921
859 sqlite3_bind_blob(ppstmt, 1, rdm.c_str(), rdm.size(), SQLITE_STATIC); 922 sqlite3_bind_blob(ppstmt, 1, rdm.c_str(), rdm.size(), SQLITE_TRANSIENT);
860 923
861 if (sqlite3_step(ppstmt) != SQLITE_DONE) 924 if (sqlite3_step(ppstmt) != SQLITE_DONE)
862 { 925 {
@@ -949,7 +1012,7 @@ int main(int argc, char** argv)
949 } 1012 }
950 1013
951 sqlite3_bind_int(ppstmt, 1, gid); 1014 sqlite3_bind_int(ppstmt, 1, gid);
952 sqlite3_bind_blob(ppstmt, 2, marshall.c_str(), marshall.length(), SQLITE_STATIC); 1015 sqlite3_bind_blob(ppstmt, 2, marshall.c_str(), marshall.length(), SQLITE_TRANSIENT);
953 1016
954 if (sqlite3_step(ppstmt) != SQLITE_DONE) 1017 if (sqlite3_step(ppstmt) != SQLITE_DONE)
955 { 1018 {
@@ -1104,7 +1167,7 @@ int main(int argc, char** argv)
1104 db_error(ppdb, query); 1167 db_error(ppdb, query);
1105 } 1168 }
1106 1169
1107 sqlite3_bind_text(ppstmt, 1, word.c_str(), word.length(), SQLITE_STATIC); 1170 sqlite3_bind_text(ppstmt, 1, word.c_str(), word.length(), SQLITE_TRANSIENT);
1108 switch (synset_id / 100000000) 1171 switch (synset_id / 100000000)
1109 { 1172 {
1110 case 1: // Noun 1173 case 1: // Noun
@@ -1119,7 +1182,7 @@ int main(int argc, char** argv)
1119 1182
1120 if (nouns.count(word) == 1) 1183 if (nouns.count(word) == 1)
1121 { 1184 {
1122 sqlite3_bind_text(ppstmt, 6, nouns[word].plural.c_str(), nouns[word].plural.length(), SQLITE_STATIC); 1185 sqlite3_bind_text(ppstmt, 6, nouns[word].plural.c_str(), nouns[word].plural.length(), SQLITE_TRANSIENT);
1123 } 1186 }
1124 1187
1125 break; 1188 break;
@@ -1132,8 +1195,8 @@ int main(int argc, char** argv)
1132 1195
1133 if (adjectives.count(word) == 1) 1196 if (adjectives.count(word) == 1)
1134 { 1197 {
1135 sqlite3_bind_text(ppstmt, 3, adjectives[word].comparative.c_str(), adjectives[word].comparative.length(), SQLITE_STATIC); 1198 sqlite3_bind_text(ppstmt, 3, adjectives[word].comparative.c_str(), adjectives[word].comparative.length(), SQLITE_TRANSIENT);
1136 sqlite3_bind_text(ppstmt, 4, adjectives[word].superlative.c_str(), adjectives[word].superlative.length(), SQLITE_STATIC); 1199 sqlite3_bind_text(ppstmt, 4, adjectives[word].superlative.c_str(), adjectives[word].superlative.length(), SQLITE_TRANSIENT);
1137 } 1200 }
1138 1201
1139 break; 1202 break;
@@ -1173,21 +1236,36 @@ int main(int argc, char** argv)
1173 { 1236 {
1174 case 1: // Noun 1237 case 1: // Noun
1175 { 1238 {
1176 query = "INSERT INTO noun_pronunciations (noun_id, pronunciation) VALUES (?, ?)"; 1239 if (!pronunciation.rhyme.empty())
1240 {
1241 query = "INSERT INTO noun_pronunciations (noun_id, pronunciation, prerhyme, rhyme) VALUES (?, ?, ?, ?)";
1242 } else {
1243 query = "INSERT INTO noun_pronunciations (noun_id, pronunciation) VALUES (?, ?)";
1244 }
1177 1245
1178 break; 1246 break;
1179 } 1247 }
1180 1248
1181 case 3: // Adjective 1249 case 3: // Adjective
1182 { 1250 {
1183 query = "INSERT INTO adjective_pronunciations (adjective_id, pronunciation) VALUES (?, ?)"; 1251 if (!pronunciation.rhyme.empty())
1252 {
1253 query = "INSERT INTO adjective_pronunciations (adjective_id, pronunciation, prerhyme, rhyme) VALUES (?, ?, ?, ?)";
1254 } else {
1255 query = "INSERT INTO adjective_pronunciations (adjective_id, pronunciation) VALUES (?, ?)";
1256 }
1184 1257
1185 break; 1258 break;
1186 } 1259 }
1187 1260
1188 case 4: // Adverb 1261 case 4: // Adverb
1189 { 1262 {
1190 query = "INSERT INTO adverb_pronunciations (adverb_id, pronunciation) VALUES (?, ?)"; 1263 if (!pronunciation.rhyme.empty())
1264 {
1265 query = "INSERT INTO adverb_pronunciations (adverb_id, pronunciation, prerhyme, rhyme) VALUES (?, ?, ?, ?)";
1266 } else {
1267 query = "INSERT INTO adverb_pronunciations (adverb_id, pronunciation) VALUES (?, ?)";
1268 }
1191 1269
1192 break; 1270 break;
1193 } 1271 }
@@ -1199,7 +1277,13 @@ int main(int argc, char** argv)
1199 } 1277 }
1200 1278
1201 sqlite3_bind_int(ppstmt, 1, rowid); 1279 sqlite3_bind_int(ppstmt, 1, rowid);
1202 sqlite3_bind_text(ppstmt, 2, pronunciation.c_str(), pronunciation.length(), SQLITE_STATIC); 1280 sqlite3_bind_text(ppstmt, 2, pronunciation.phonemes.c_str(), pronunciation.phonemes.length(), SQLITE_TRANSIENT);
1281
1282 if (!pronunciation.rhyme.empty())
1283 {
1284 sqlite3_bind_text(ppstmt, 3, pronunciation.prerhyme.c_str(), pronunciation.prerhyme.length(), SQLITE_TRANSIENT);
1285 sqlite3_bind_text(ppstmt, 4, pronunciation.rhyme.c_str(), pronunciation.rhyme.length(), SQLITE_TRANSIENT);
1286 }
1203 1287
1204 if (sqlite3_step(ppstmt) != SQLITE_DONE) 1288 if (sqlite3_step(ppstmt) != SQLITE_DONE)
1205 { 1289 {
@@ -2188,7 +2272,7 @@ int main(int argc, char** argv)
2188 db_error(ppdb, query); 2272 db_error(ppdb, query);
2189 } 2273 }
2190 2274
2191 sqlite3_bind_text(ppstmt, 1, syn.c_str(), 1, SQLITE_STATIC); 2275 sqlite3_bind_text(ppstmt, 1, syn.c_str(), 1, SQLITE_TRANSIENT);
2192 sqlite3_bind_int(ppstmt, 2, wn[synset_id][wnum]); 2276 sqlite3_bind_int(ppstmt, 2, wn[synset_id][wnum]);
2193 2277
2194 if (sqlite3_step(ppstmt) != SQLITE_DONE) 2278 if (sqlite3_step(ppstmt) != SQLITE_DONE)
diff --git a/generator/schema.sql b/generator/schema.sql index 9a39944..1836c62 100644 --- a/generator/schema.sql +++ b/generator/schema.sql
@@ -184,6 +184,8 @@ DROP TABLE IF EXISTS `noun_pronunciations`;
184CREATE TABLE `noun_pronunciations` ( 184CREATE TABLE `noun_pronunciations` (
185 `noun_id` INTEGER NOT NULL, 185 `noun_id` INTEGER NOT NULL,
186 `pronunciation` VARCHAR(64) NOT NULL, 186 `pronunciation` VARCHAR(64) NOT NULL,
187 `prerhyme` VARCHAR(8),
188 `rhyme` VARCHAR(64),
187 FOREIGN KEY (`noun_id`) REFERENCES `nouns`(`noun_id`) 189 FOREIGN KEY (`noun_id`) REFERENCES `nouns`(`noun_id`)
188); 190);
189 191
@@ -191,6 +193,8 @@ DROP TABLE IF EXISTS `verb_pronunciations`;
191CREATE TABLE `verb_pronunciations` ( 193CREATE TABLE `verb_pronunciations` (
192 `verb_id` INTEGER NOT NULL, 194 `verb_id` INTEGER NOT NULL,
193 `pronunciation` VARCHAR(64) NOT NULL, 195 `pronunciation` VARCHAR(64) NOT NULL,
196 `prerhyme` VARCHAR(8),
197 `rhyme` VARCHAR(64),
194 FOREIGN KEY (`verb_id`) REFERENCES `verbs`(`verb_id`) 198 FOREIGN KEY (`verb_id`) REFERENCES `verbs`(`verb_id`)
195); 199);
196 200
@@ -198,6 +202,8 @@ DROP TABLE IF EXISTS `adjective_pronunciations`;
198CREATE TABLE `adjective_pronunciations` ( 202CREATE TABLE `adjective_pronunciations` (
199 `adjective_id` INTEGER NOT NULL, 203 `adjective_id` INTEGER NOT NULL,
200 `pronunciation` VARCHAR(64) NOT NULL, 204 `pronunciation` VARCHAR(64) NOT NULL,
205 `prerhyme` VARCHAR(8),
206 `rhyme` VARCHAR(64),
201 FOREIGN KEY (`adjective_id`) REFERENCES `adjectives`(`adjective_id`) 207 FOREIGN KEY (`adjective_id`) REFERENCES `adjectives`(`adjective_id`)
202); 208);
203 209
@@ -205,6 +211,8 @@ DROP TABLE IF EXISTS `adverb_pronunciations`;
205CREATE TABLE `adverb_pronunciations` ( 211CREATE TABLE `adverb_pronunciations` (
206 `adverb_id` INTEGER NOT NULL, 212 `adverb_id` INTEGER NOT NULL,
207 `pronunciation` VARCHAR(64) NOT NULL, 213 `pronunciation` VARCHAR(64) NOT NULL,
214 `prerhyme` VARCHAR(8),
215 `rhyme` VARCHAR(64),
208 FOREIGN KEY (`adverb_id`) REFERENCES `adverbs`(`adverb_id`) 216 FOREIGN KEY (`adverb_id`) REFERENCES `adverbs`(`adverb_id`)
209); 217);
210 218
diff --git a/lib/adjective_query.cpp b/lib/adjective_query.cpp index a7f915c..2bea68f 100644 --- a/lib/adjective_query.cpp +++ b/lib/adjective_query.cpp
@@ -33,7 +33,7 @@ namespace verbly {
33 33
34 adjective_query& adjective_query::rhymes_with(const word& _word) 34 adjective_query& adjective_query::rhymes_with(const word& _word)
35 { 35 {
36 for (auto rhyme : _word.rhyme_phonemes()) 36 for (auto rhyme : _word.get_rhymes())
37 { 37 {
38 _rhymes.push_back(rhyme); 38 _rhymes.push_back(rhyme);
39 } 39 }
@@ -53,6 +53,34 @@ namespace verbly {
53 return *this; 53 return *this;
54 } 54 }
55 55
56 adjective_query& adjective_query::has_rhyming_noun()
57 {
58 _has_rhyming_noun = true;
59
60 return *this;
61 }
62
63 adjective_query& adjective_query::has_rhyming_adjective()
64 {
65 _has_rhyming_adjective = true;
66
67 return *this;
68 }
69
70 adjective_query& adjective_query::has_rhyming_adverb()
71 {
72 _has_rhyming_adverb = true;
73
74 return *this;
75 }
76
77 adjective_query& adjective_query::has_rhyming_verb()
78 {
79 _has_rhyming_verb = true;
80
81 return *this;
82 }
83
56 adjective_query& adjective_query::with_prefix(filter<std::string> _f) 84 adjective_query& adjective_query::with_prefix(filter<std::string> _f)
57 { 85 {
58 _f.clean(); 86 _f.clean();
@@ -227,16 +255,37 @@ namespace verbly {
227 255
228 if (!_rhymes.empty()) 256 if (!_rhymes.empty())
229 { 257 {
230 std::list<std::string> clauses(_rhymes.size(), "pronunciation LIKE ?"); 258 std::list<std::string> clauses(_rhymes.size(), "(prerhyme != ? AND rhyme = ?)");
231 std::string cond = "adjective_id IN (SELECT adjective_id FROM adjective_pronunciations WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; 259 std::string cond = "adjective_id IN (SELECT adjective_id FROM adjective_pronunciations WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
232 conditions.push_back(cond); 260 conditions.push_back(cond);
233 261
234 for (auto rhyme : _rhymes) 262 for (auto rhy : _rhymes)
235 { 263 {
236 bindings.emplace_back("%" + rhyme); 264 bindings.emplace_back(rhy.get_prerhyme());
265 bindings.emplace_back(rhy.get_rhyme());
237 } 266 }
238 } 267 }
239 268
269 if (_has_rhyming_noun)
270 {
271 conditions.push_back("adjective_id IN (SELECT a.adjective_id FROM adjectives AS a INNER JOIN adjective_pronunciations AS curp ON curp.adjective_id = a.adjective_id INNER JOIN noun_pronunciations AS rhmp ON rhmp.prerhyme != curp.prerhyme AND rhmp.rhyme = curp.rhyme)");
272 }
273
274 if (_has_rhyming_adjective)
275 {
276 conditions.push_back("adjective_id IN (SELECT a.adjective_id FROM adjectives AS a INNER JOIN adjective_pronunciations AS curp ON curp.adjective_id = a.adjective_id INNER JOIN adjective_pronunciations AS rhmp ON rhmp.prerhyme != curp.prerhyme AND rhmp.rhyme = curp.rhyme AND rhmp.adjective_id != curp.adjective_id)");
277 }
278
279 if (_has_rhyming_adverb)
280 {
281 conditions.push_back("adjective_id IN (SELECT a.adjective_id FROM adjectives AS a INNER JOIN adjective_pronunciations AS curp ON curp.adjective_id = a.adjective_id INNER JOIN adverb_pronunciations AS rhmp ON rhmp.prerhyme != curp.prerhyme AND rhmp.rhyme = curp.rhyme)");
282 }
283
284 if (_has_rhyming_verb)
285 {
286 conditions.push_back("adjective_id IN (SELECT a.adjective_id FROM adjectives AS a INNER JOIN adjective_pronunciations AS curp ON curp.adjective_id = a.adjective_id INNER JOIN verb_pronunciations AS rhmp ON rhmp.prerhyme != curp.prerhyme AND rhmp.rhyme = curp.rhyme)");
287 }
288
240 for (auto except : _except) 289 for (auto except : _except)
241 { 290 {
242 conditions.push_back("adjective_id != ?"); 291 conditions.push_back("adjective_id != ?");
@@ -816,7 +865,7 @@ namespace verbly {
816 865
817 case binding::type::string: 866 case binding::type::string:
818 { 867 {
819 sqlite3_bind_text(ppstmt, i, binding.get_string().c_str(), binding.get_string().length(), SQLITE_STATIC); 868 sqlite3_bind_text(ppstmt, i, binding.get_string().c_str(), binding.get_string().length(), SQLITE_TRANSIENT);
820 869
821 break; 870 break;
822 } 871 }
@@ -894,7 +943,7 @@ namespace verbly {
894 943
895 for (auto& adjective : output) 944 for (auto& adjective : output)
896 { 945 {
897 query = "SELECT pronunciation FROM adjective_pronunciations WHERE adjective_id = ?"; 946 query = "SELECT pronunciation, prerhyme, rhyme FROM adjective_pronunciations WHERE adjective_id = ?";
898 if (sqlite3_prepare_v2(_data.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK) 947 if (sqlite3_prepare_v2(_data.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK)
899 { 948 {
900 throw std::runtime_error(sqlite3_errmsg(_data.ppdb)); 949 throw std::runtime_error(sqlite3_errmsg(_data.ppdb));
@@ -908,6 +957,13 @@ namespace verbly {
908 auto phonemes = verbly::split<std::list<std::string>>(pronunciation, " "); 957 auto phonemes = verbly::split<std::list<std::string>>(pronunciation, " ");
909 958
910 adjective.pronunciations.push_back(phonemes); 959 adjective.pronunciations.push_back(phonemes);
960
961 if ((sqlite3_column_type(ppstmt, 1) != SQLITE_NULL) && (sqlite3_column_type(ppstmt, 2) != SQLITE_NULL))
962 {
963 std::string prerhyme(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 1)));
964 std::string rhyming(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 2)));
965 adjective.rhymes.emplace_back(prerhyme, rhyming);
966 }
911 } 967 }
912 968
913 sqlite3_finalize(ppstmt); 969 sqlite3_finalize(ppstmt);
diff --git a/lib/adjective_query.h b/lib/adjective_query.h index b2859dc..030a494 100644 --- a/lib/adjective_query.h +++ b/lib/adjective_query.h
@@ -12,6 +12,10 @@ namespace verbly {
12 adjective_query& except(const adjective& _word); 12 adjective_query& except(const adjective& _word);
13 adjective_query& rhymes_with(const word& _word); 13 adjective_query& rhymes_with(const word& _word);
14 adjective_query& has_pronunciation(); 14 adjective_query& has_pronunciation();
15 adjective_query& has_rhyming_noun();
16 adjective_query& has_rhyming_adjective();
17 adjective_query& has_rhyming_adverb();
18 adjective_query& has_rhyming_verb();
15 19
16 adjective_query& requires_comparative_form(); 20 adjective_query& requires_comparative_form();
17 adjective_query& requires_superlative_form(); 21 adjective_query& requires_superlative_form();
@@ -54,9 +58,13 @@ namespace verbly {
54 const data& _data; 58 const data& _data;
55 int _limit = unlimited; 59 int _limit = unlimited;
56 bool _random = false; 60 bool _random = false;
57 std::list<std::string> _rhymes; 61 std::list<rhyme> _rhymes;
58 std::list<adjective> _except; 62 std::list<adjective> _except;
59 bool _has_prn = false; 63 bool _has_prn = false;
64 bool _has_rhyming_noun = false;
65 bool _has_rhyming_adjective = false;
66 bool _has_rhyming_adverb = false;
67 bool _has_rhyming_verb = false;
60 68
61 bool _requires_comparative_form = false; 69 bool _requires_comparative_form = false;
62 bool _requires_superlative_form = false; 70 bool _requires_superlative_form = false;
diff --git a/lib/adverb_query.cpp b/lib/adverb_query.cpp index 30ba92b..797e6a6 100644 --- a/lib/adverb_query.cpp +++ b/lib/adverb_query.cpp
@@ -33,7 +33,7 @@ namespace verbly {
33 33
34 adverb_query& adverb_query::rhymes_with(const word& _word) 34 adverb_query& adverb_query::rhymes_with(const word& _word)
35 { 35 {
36 for (auto rhyme : _word.rhyme_phonemes()) 36 for (auto rhyme : _word.get_rhymes())
37 { 37 {
38 _rhymes.push_back(rhyme); 38 _rhymes.push_back(rhyme);
39 } 39 }
@@ -53,6 +53,34 @@ namespace verbly {
53 return *this; 53 return *this;
54 } 54 }
55 55
56 adverb_query& adverb_query::has_rhyming_noun()
57 {
58 _has_rhyming_noun = true;
59
60 return *this;
61 }
62
63 adverb_query& adverb_query::has_rhyming_adjective()
64 {
65 _has_rhyming_adjective = true;
66
67 return *this;
68 }
69
70 adverb_query& adverb_query::has_rhyming_adverb()
71 {
72 _has_rhyming_adverb = true;
73
74 return *this;
75 }
76
77 adverb_query& adverb_query::has_rhyming_verb()
78 {
79 _has_rhyming_verb = true;
80
81 return *this;
82 }
83
56 adverb_query& adverb_query::requires_comparative_form() 84 adverb_query& adverb_query::requires_comparative_form()
57 { 85 {
58 _requires_comparative_form = true; 86 _requires_comparative_form = true;
@@ -181,16 +209,37 @@ namespace verbly {
181 209
182 if (!_rhymes.empty()) 210 if (!_rhymes.empty())
183 { 211 {
184 std::list<std::string> clauses(_rhymes.size(), "pronunciation LIKE ?"); 212 std::list<std::string> clauses(_rhymes.size(), "(prerhyme != ? AND rhyme = ?)");
185 std::string cond = "adverb_id IN (SELECT adverb_id FROM adverb_pronunciations WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; 213 std::string cond = "adverb_id IN (SELECT adverb_id FROM adverb_pronunciations WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
186 conditions.push_back(cond); 214 conditions.push_back(cond);
187 215
188 for (auto rhyme : _rhymes) 216 for (auto rhy : _rhymes)
189 { 217 {
190 bindings.emplace_back("%" + rhyme); 218 bindings.emplace_back(rhy.get_prerhyme());
219 bindings.emplace_back(rhy.get_rhyme());
191 } 220 }
192 } 221 }
193 222
223 if (_has_rhyming_noun)
224 {
225 conditions.push_back("adverb_id IN (SELECT a.adverb_id FROM adverbs AS a INNER JOIN adverb_pronunciations AS curp ON curp.noun_id = a.adverb_id INNER JOIN noun_pronunciations AS rhmp ON rhmp.prerhyme != curp.prerhyme AND rhmp.rhyme = curp.rhyme)");
226 }
227
228 if (_has_rhyming_adjective)
229 {
230 conditions.push_back("adverb_id IN (SELECT a.adverb_id FROM adverbs AS a INNER JOIN adverb_pronunciations AS curp ON curp.noun_id = a.adverb_id INNER JOIN adjective_pronunciations AS rhmp ON rhmp.prerhyme != curp.prerhyme AND rhmp.rhyme = curp.rhyme)");
231 }
232
233 if (_has_rhyming_adverb)
234 {
235 conditions.push_back("adverb_id IN (SELECT a.adverb_id FROM adverbs AS a INNER JOIN adverb_pronunciations AS curp ON curp.noun_id = a.adverb_id INNER JOIN adverb_pronunciations AS rhmp ON rhmp.prerhyme != curp.prerhyme AND rhmp.rhyme = curp.rhyme AND rhmp.adverb_id != curp.adverb_id)");
236 }
237
238 if (_has_rhyming_verb)
239 {
240 conditions.push_back("adverb_id IN (SELECT a.adverb_id FROM adverbs AS a INNER JOIN adverb_pronunciations AS curp ON curp.noun_id = a.adverb_id INNER JOIN verb_pronunciations AS rhmp ON rhmp.prerhyme != curp.prerhyme AND rhmp.rhyme = curp.rhyme)");
241 }
242
194 for (auto except : _except) 243 for (auto except : _except)
195 { 244 {
196 conditions.push_back("adverb_id != ?"); 245 conditions.push_back("adverb_id != ?");
@@ -538,7 +587,7 @@ namespace verbly {
538 587
539 case binding::type::string: 588 case binding::type::string:
540 { 589 {
541 sqlite3_bind_text(ppstmt, i, binding.get_string().c_str(), binding.get_string().length(), SQLITE_STATIC); 590 sqlite3_bind_text(ppstmt, i, binding.get_string().c_str(), binding.get_string().length(), SQLITE_TRANSIENT);
542 591
543 break; 592 break;
544 } 593 }
@@ -601,7 +650,7 @@ namespace verbly {
601 650
602 for (auto& adverb : output) 651 for (auto& adverb : output)
603 { 652 {
604 query = "SELECT pronunciation FROM adverb_pronunciations WHERE adverb_id = ?"; 653 query = "SELECT pronunciation, prerhyme, rhyme FROM adverb_pronunciations WHERE adverb_id = ?";
605 if (sqlite3_prepare_v2(_data.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK) 654 if (sqlite3_prepare_v2(_data.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK)
606 { 655 {
607 throw std::runtime_error(sqlite3_errmsg(_data.ppdb)); 656 throw std::runtime_error(sqlite3_errmsg(_data.ppdb));
@@ -615,6 +664,13 @@ namespace verbly {
615 auto phonemes = verbly::split<std::list<std::string>>(pronunciation, " "); 664 auto phonemes = verbly::split<std::list<std::string>>(pronunciation, " ");
616 665
617 adverb.pronunciations.push_back(phonemes); 666 adverb.pronunciations.push_back(phonemes);
667
668 if ((sqlite3_column_type(ppstmt, 1) != SQLITE_NULL) && (sqlite3_column_type(ppstmt, 2) != SQLITE_NULL))
669 {
670 std::string prerhyme(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 1)));
671 std::string rhyming(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 2)));
672 adverb.rhymes.emplace_back(prerhyme, rhyming);
673 }
618 } 674 }
619 675
620 sqlite3_finalize(ppstmt); 676 sqlite3_finalize(ppstmt);
diff --git a/lib/adverb_query.h b/lib/adverb_query.h index e9354bb..403a616 100644 --- a/lib/adverb_query.h +++ b/lib/adverb_query.h
@@ -12,6 +12,10 @@ namespace verbly {
12 adverb_query& except(const adverb& _word); 12 adverb_query& except(const adverb& _word);
13 adverb_query& rhymes_with(const word& _word); 13 adverb_query& rhymes_with(const word& _word);
14 adverb_query& has_pronunciation(); 14 adverb_query& has_pronunciation();
15 adverb_query& has_rhyming_noun();
16 adverb_query& has_rhyming_adjective();
17 adverb_query& has_rhyming_adverb();
18 adverb_query& has_rhyming_verb();
15 19
16 adverb_query& requires_comparative_form(); 20 adverb_query& requires_comparative_form();
17 adverb_query& requires_superlative_form(); 21 adverb_query& requires_superlative_form();
@@ -41,9 +45,13 @@ namespace verbly {
41 const data& _data; 45 const data& _data;
42 int _limit = unlimited; 46 int _limit = unlimited;
43 bool _random = false; 47 bool _random = false;
44 std::list<std::string> _rhymes; 48 std::list<rhyme> _rhymes;
45 std::list<adverb> _except; 49 std::list<adverb> _except;
46 bool _has_prn = false; 50 bool _has_prn = false;
51 bool _has_rhyming_noun = false;
52 bool _has_rhyming_adjective = false;
53 bool _has_rhyming_adverb = false;
54 bool _has_rhyming_verb = false;
47 55
48 bool _requires_comparative_form = false; 56 bool _requires_comparative_form = false;
49 bool _requires_superlative_form = false; 57 bool _requires_superlative_form = false;
diff --git a/lib/data.cpp b/lib/data.cpp index c14956f..db42487 100644 --- a/lib/data.cpp +++ b/lib/data.cpp
@@ -1,7 +1,7 @@
1#include "verbly.h" 1#include "verbly.h"
2 2
3namespace verbly { 3namespace verbly {
4 4
5 data::data(std::string datafile) 5 data::data(std::string datafile)
6 { 6 {
7 if (sqlite3_open_v2(datafile.c_str(), &ppdb, SQLITE_OPEN_READONLY, NULL) != SQLITE_OK) 7 if (sqlite3_open_v2(datafile.c_str(), &ppdb, SQLITE_OPEN_READONLY, NULL) != SQLITE_OK)
diff --git a/lib/frame_query.cpp b/lib/frame_query.cpp index 3c4a3e8..11f0432 100644 --- a/lib/frame_query.cpp +++ b/lib/frame_query.cpp
@@ -73,7 +73,7 @@ namespace verbly {
73 73
74 case binding::type::string: 74 case binding::type::string:
75 { 75 {
76 sqlite3_bind_text(ppstmt, i, binding.get_string().c_str(), binding.get_string().length(), SQLITE_STATIC); 76 sqlite3_bind_text(ppstmt, i, binding.get_string().c_str(), binding.get_string().length(), SQLITE_TRANSIENT);
77 77
78 break; 78 break;
79 } 79 }
diff --git a/lib/noun_query.cpp b/lib/noun_query.cpp index 19a1297..b4336b6 100644 --- a/lib/noun_query.cpp +++ b/lib/noun_query.cpp
@@ -33,7 +33,7 @@ namespace verbly {
33 33
34 noun_query& noun_query::rhymes_with(const word& _word) 34 noun_query& noun_query::rhymes_with(const word& _word)
35 { 35 {
36 for (auto rhyme : _word.rhyme_phonemes()) 36 for (auto rhyme : _word.get_rhymes())
37 { 37 {
38 _rhymes.push_back(rhyme); 38 _rhymes.push_back(rhyme);
39 } 39 }
@@ -53,6 +53,34 @@ namespace verbly {
53 return *this; 53 return *this;
54 } 54 }
55 55
56 noun_query& noun_query::has_rhyming_noun()
57 {
58 _has_rhyming_noun = true;
59
60 return *this;
61 }
62
63 noun_query& noun_query::has_rhyming_adjective()
64 {
65 _has_rhyming_adjective = true;
66
67 return *this;
68 }
69
70 noun_query& noun_query::has_rhyming_adverb()
71 {
72 _has_rhyming_adverb = true;
73
74 return *this;
75 }
76
77 noun_query& noun_query::has_rhyming_verb()
78 {
79 _has_rhyming_verb = true;
80
81 return *this;
82 }
83
56 noun_query& noun_query::with_singular_form(std::string _arg) 84 noun_query& noun_query::with_singular_form(std::string _arg)
57 { 85 {
58 _with_singular_form.push_back(_arg); 86 _with_singular_form.push_back(_arg);
@@ -483,16 +511,37 @@ namespace verbly {
483 511
484 if (!_rhymes.empty()) 512 if (!_rhymes.empty())
485 { 513 {
486 std::list<std::string> clauses(_rhymes.size(), "pronunciation LIKE ?"); 514 std::list<std::string> clauses(_rhymes.size(), "(prerhyme != ? AND rhyme = ?)");
487 std::string cond = "noun_id IN (SELECT noun_id FROM noun_pronunciations WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; 515 std::string cond = "noun_id IN (SELECT noun_id FROM noun_pronunciations WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
488 conditions.push_back(cond); 516 conditions.push_back(cond);
489 517
490 for (auto rhyme : _rhymes) 518 for (auto rhy : _rhymes)
491 { 519 {
492 bindings.emplace_back("%" + rhyme); 520 bindings.emplace_back(rhy.get_prerhyme());
521 bindings.emplace_back(rhy.get_rhyme());
493 } 522 }
494 } 523 }
495 524
525 if (_has_rhyming_noun)
526 {
527 conditions.push_back("noun_id IN (SELECT a.noun_id FROM nouns AS a INNER JOIN noun_pronunciations AS curp ON curp.noun_id = a.noun_id INNER JOIN noun_pronunciations AS rhmp ON rhmp.prerhyme != curp.prerhyme AND rhmp.rhyme = curp.rhyme AND rhmp.noun_id != curp.noun_id)");
528 }
529
530 if (_has_rhyming_adjective)
531 {
532 conditions.push_back("noun_id IN (SELECT a.noun_id FROM nouns AS a INNER JOIN noun_pronunciations AS curp ON curp.noun_id = a.noun_id INNER JOIN adjective_pronunciations AS rhmp ON rhmp.prerhyme != curp.prerhyme AND rhmp.rhyme = curp.rhyme)");
533 }
534
535 if (_has_rhyming_adverb)
536 {
537 conditions.push_back("noun_id IN (SELECT a.noun_id FROM nouns AS a INNER JOIN noun_pronunciations AS curp ON curp.noun_id = a.noun_id INNER JOIN adverb_pronunciations AS rhmp ON rhmp.prerhyme != curp.prerhyme AND rhmp.rhyme = curp.rhyme)");
538 }
539
540 if (_has_rhyming_verb)
541 {
542 conditions.push_back("noun_id IN (SELECT a.noun_id FROM nouns AS a INNER JOIN noun_pronunciations AS curp ON curp.noun_id = a.noun_id INNER JOIN verb_pronunciations AS rhmp ON rhmp.prerhyme != curp.prerhyme AND rhmp.rhyme = curp.rhyme)");
543 }
544
496 for (auto except : _except) 545 for (auto except : _except)
497 { 546 {
498 conditions.push_back("noun_id != ?"); 547 conditions.push_back("noun_id != ?");
@@ -1768,7 +1817,7 @@ namespace verbly {
1768 { 1817 {
1769 throw std::runtime_error(sqlite3_errmsg(_data.ppdb)); 1818 throw std::runtime_error(sqlite3_errmsg(_data.ppdb));
1770 } 1819 }
1771 1820
1772 int i = 1; 1821 int i = 1;
1773 for (auto& binding : bindings) 1822 for (auto& binding : bindings)
1774 { 1823 {
@@ -1783,7 +1832,7 @@ namespace verbly {
1783 1832
1784 case binding::type::string: 1833 case binding::type::string:
1785 { 1834 {
1786 sqlite3_bind_text(ppstmt, i, binding.get_string().c_str(), binding.get_string().length(), SQLITE_STATIC); 1835 sqlite3_bind_text(ppstmt, i, binding.get_string().c_str(), binding.get_string().length(), SQLITE_TRANSIENT);
1787 1836
1788 break; 1837 break;
1789 } 1838 }
@@ -1791,7 +1840,7 @@ namespace verbly {
1791 1840
1792 i++; 1841 i++;
1793 } 1842 }
1794 1843
1795 /* 1844 /*
1796 for (auto adj : _derived_from_adjective) 1845 for (auto adj : _derived_from_adjective)
1797 { 1846 {
@@ -1843,7 +1892,7 @@ namespace verbly {
1843 1892
1844 for (auto& noun : output) 1893 for (auto& noun : output)
1845 { 1894 {
1846 query = "SELECT pronunciation FROM noun_pronunciations WHERE noun_id = ?"; 1895 query = "SELECT pronunciation, prerhyme, rhyme FROM noun_pronunciations WHERE noun_id = ?";
1847 if (sqlite3_prepare_v2(_data.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK) 1896 if (sqlite3_prepare_v2(_data.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK)
1848 { 1897 {
1849 throw std::runtime_error(sqlite3_errmsg(_data.ppdb)); 1898 throw std::runtime_error(sqlite3_errmsg(_data.ppdb));
@@ -1857,6 +1906,14 @@ namespace verbly {
1857 auto phonemes = verbly::split<std::list<std::string>>(pronunciation, " "); 1906 auto phonemes = verbly::split<std::list<std::string>>(pronunciation, " ");
1858 1907
1859 noun.pronunciations.push_back(phonemes); 1908 noun.pronunciations.push_back(phonemes);
1909
1910 if ((sqlite3_column_type(ppstmt, 1) != SQLITE_NULL) && (sqlite3_column_type(ppstmt, 2) != SQLITE_NULL))
1911 {
1912 std::string prerhyme(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 1)));
1913 std::string rhyming(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 2)));
1914
1915 noun.rhymes.emplace_back(prerhyme, rhyming);
1916 }
1860 } 1917 }
1861 1918
1862 sqlite3_finalize(ppstmt); 1919 sqlite3_finalize(ppstmt);
diff --git a/lib/noun_query.h b/lib/noun_query.h index 8768f5d..6b5733f 100644 --- a/lib/noun_query.h +++ b/lib/noun_query.h
@@ -12,6 +12,10 @@ namespace verbly {
12 noun_query& except(const noun& _word); 12 noun_query& except(const noun& _word);
13 noun_query& rhymes_with(const word& _word); 13 noun_query& rhymes_with(const word& _word);
14 noun_query& has_pronunciation(); 14 noun_query& has_pronunciation();
15 noun_query& has_rhyming_noun();
16 noun_query& has_rhyming_adjective();
17 noun_query& has_rhyming_adverb();
18 noun_query& has_rhyming_verb();
15 19
16 noun_query& with_singular_form(std::string _arg); 20 noun_query& with_singular_form(std::string _arg);
17 noun_query& with_prefix(filter<std::string> _f); 21 noun_query& with_prefix(filter<std::string> _f);
@@ -86,9 +90,13 @@ namespace verbly {
86 const data& _data; 90 const data& _data;
87 int _limit = unlimited; 91 int _limit = unlimited;
88 bool _random = false; 92 bool _random = false;
89 std::list<std::string> _rhymes; 93 std::list<rhyme> _rhymes;
90 std::list<noun> _except; 94 std::list<noun> _except;
91 bool _has_prn = false; 95 bool _has_prn = false;
96 bool _has_rhyming_noun = false;
97 bool _has_rhyming_adjective = false;
98 bool _has_rhyming_adverb = false;
99 bool _has_rhyming_verb = false;
92 100
93 std::list<std::string> _with_singular_form; 101 std::list<std::string> _with_singular_form;
94 filter<std::string> _with_prefix; 102 filter<std::string> _with_prefix;
diff --git a/lib/preposition.cpp b/lib/preposition.cpp index 8df13aa..cea9165 100644 --- a/lib/preposition.cpp +++ b/lib/preposition.cpp
@@ -83,7 +83,7 @@ namespace verbly {
83 83
84 case binding::type::string: 84 case binding::type::string:
85 { 85 {
86 sqlite3_bind_text(ppstmt, i, binding.get_string().c_str(), binding.get_string().length(), SQLITE_STATIC); 86 sqlite3_bind_text(ppstmt, i, binding.get_string().c_str(), binding.get_string().length(), SQLITE_TRANSIENT);
87 87
88 break; 88 break;
89 } 89 }
diff --git a/lib/verb_query.cpp b/lib/verb_query.cpp index 929ecc7..654bc33 100644 --- a/lib/verb_query.cpp +++ b/lib/verb_query.cpp
@@ -33,7 +33,7 @@ namespace verbly {
33 33
34 verb_query& verb_query::rhymes_with(const word& _word) 34 verb_query& verb_query::rhymes_with(const word& _word)
35 { 35 {
36 for (auto rhyme : _word.rhyme_phonemes()) 36 for (auto rhyme : _word.get_rhymes())
37 { 37 {
38 _rhymes.push_back(rhyme); 38 _rhymes.push_back(rhyme);
39 } 39 }
@@ -53,6 +53,34 @@ namespace verbly {
53 return *this; 53 return *this;
54 } 54 }
55 55
56 verb_query& verb_query::has_rhyming_noun()
57 {
58 _has_rhyming_noun = true;
59
60 return *this;
61 }
62
63 verb_query& verb_query::has_rhyming_adjective()
64 {
65 _has_rhyming_adjective = true;
66
67 return *this;
68 }
69
70 verb_query& verb_query::has_rhyming_adverb()
71 {
72 _has_rhyming_adverb = true;
73
74 return *this;
75 }
76
77 verb_query& verb_query::has_rhyming_verb()
78 {
79 _has_rhyming_verb = true;
80
81 return *this;
82 }
83
56 verb_query& verb_query::has_frames() 84 verb_query& verb_query::has_frames()
57 { 85 {
58 this->_has_frames = true; 86 this->_has_frames = true;
@@ -74,16 +102,37 @@ namespace verbly {
74 102
75 if (!_rhymes.empty()) 103 if (!_rhymes.empty())
76 { 104 {
77 std::list<std::string> clauses(_rhymes.size(), "pronunciation LIKE ?"); 105 std::list<std::string> clauses(_rhymes.size(), "(prerhyme != ? AND rhyme = ?)");
78 std::string cond = "verb_id IN (SELECT verb_id FROM verb_pronunciations WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; 106 std::string cond = "verb_id IN (SELECT verb_id FROM verb_pronunciations WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
79 conditions.push_back(cond); 107 conditions.push_back(cond);
80 108
81 for (auto rhyme : _rhymes) 109 for (auto rhy : _rhymes)
82 { 110 {
83 bindings.emplace_back("%" + rhyme); 111 bindings.emplace_back(rhy.get_prerhyme());
112 bindings.emplace_back(rhy.get_rhyme());
84 } 113 }
85 } 114 }
86 115
116 if (_has_rhyming_noun)
117 {
118 conditions.push_back("verb_id IN (SELECT a.verb_id FROM verbs AS a INNER JOIN verb_pronunciations AS curp ON curp.noun_id = a.adverb_id INNER JOIN noun_pronunciations AS rhmp ON rhmp.prerhyme != curp.prerhyme AND rhmp.rhyme = curp.rhyme)");
119 }
120
121 if (_has_rhyming_adjective)
122 {
123 conditions.push_back("verb_id IN (SELECT a.verb_id FROM verbs AS a INNER JOIN verb_pronunciations AS curp ON curp.noun_id = a.adverb_id INNER JOIN adjective_pronunciations AS rhmp ON rhmp.prerhyme != curp.prerhyme AND rhmp.rhyme = curp.rhyme)");
124 }
125
126 if (_has_rhyming_adverb)
127 {
128 conditions.push_back("verb_id IN (SELECT a.verb_id FROM verbs AS a INNER JOIN verb_pronunciations AS curp ON curp.noun_id = a.adverb_id INNER JOIN adverb_pronunciations AS rhmp ON rhmp.prerhyme != curp.prerhyme AND rhmp.rhyme = curp.rhyme)");
129 }
130
131 if (_has_rhyming_verb)
132 {
133 conditions.push_back("verb_id IN (SELECT a.verb_id FROM verbs AS a INNER JOIN verb_pronunciations AS curp ON curp.noun_id = a.adverb_id INNER JOIN verb_pronunciations AS rhmp ON rhmp.prerhyme != curp.prerhyme AND rhmp.rhyme = curp.rhyme AND rhmp.verb_id != curp.verb_id)");
134 }
135
87 for (auto except : _except) 136 for (auto except : _except)
88 { 137 {
89 conditions.push_back("verb_id != ?"); 138 conditions.push_back("verb_id != ?");
@@ -132,7 +181,7 @@ namespace verbly {
132 181
133 case binding::type::string: 182 case binding::type::string:
134 { 183 {
135 sqlite3_bind_text(ppstmt, i, binding.get_string().c_str(), binding.get_string().length(), SQLITE_STATIC); 184 sqlite3_bind_text(ppstmt, i, binding.get_string().c_str(), binding.get_string().length(), SQLITE_TRANSIENT);
136 185
137 break; 186 break;
138 } 187 }
@@ -158,7 +207,7 @@ namespace verbly {
158 207
159 for (auto& verb : output) 208 for (auto& verb : output)
160 { 209 {
161 query = "SELECT pronunciation FROM verb_pronunciations WHERE verb_id = ?"; 210 query = "SELECT pronunciation, prerhyme, rhyme FROM verb_pronunciations WHERE verb_id = ?";
162 if (sqlite3_prepare_v2(_data.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK) 211 if (sqlite3_prepare_v2(_data.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK)
163 { 212 {
164 throw std::runtime_error(sqlite3_errmsg(_data.ppdb)); 213 throw std::runtime_error(sqlite3_errmsg(_data.ppdb));
@@ -172,6 +221,13 @@ namespace verbly {
172 auto phonemes = verbly::split<std::list<std::string>>(pronunciation, " "); 221 auto phonemes = verbly::split<std::list<std::string>>(pronunciation, " ");
173 222
174 verb.pronunciations.push_back(phonemes); 223 verb.pronunciations.push_back(phonemes);
224
225 if ((sqlite3_column_type(ppstmt, 1) != SQLITE_NULL) && (sqlite3_column_type(ppstmt, 2) != SQLITE_NULL))
226 {
227 std::string prerhyme(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 1)));
228 std::string rhyming(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 2)));
229 verb.rhymes.emplace_back(prerhyme, rhyming);
230 }
175 } 231 }
176 232
177 sqlite3_finalize(ppstmt); 233 sqlite3_finalize(ppstmt);
diff --git a/lib/verb_query.h b/lib/verb_query.h index 24f5732..a07dc18 100644 --- a/lib/verb_query.h +++ b/lib/verb_query.h
@@ -12,6 +12,10 @@ namespace verbly {
12 verb_query& except(const verb& _word); 12 verb_query& except(const verb& _word);
13 verb_query& rhymes_with(const word& _word); 13 verb_query& rhymes_with(const word& _word);
14 verb_query& has_pronunciation(); 14 verb_query& has_pronunciation();
15 verb_query& has_rhyming_noun();
16 verb_query& has_rhyming_adjective();
17 verb_query& has_rhyming_adverb();
18 verb_query& has_rhyming_verb();
15 19
16 verb_query& has_frames(); 20 verb_query& has_frames();
17 21
@@ -23,10 +27,14 @@ namespace verbly {
23 const data& _data; 27 const data& _data;
24 int _limit = unlimited; 28 int _limit = unlimited;
25 bool _random = false; 29 bool _random = false;
26 std::list<std::string> _rhymes; 30 std::list<rhyme> _rhymes;
27 std::list<verb> _except; 31 std::list<verb> _except;
28 bool _has_prn = false; 32 bool _has_prn = false;
29 bool _has_frames = false; 33 bool _has_frames = false;
34 bool _has_rhyming_noun = false;
35 bool _has_rhyming_adjective = false;
36 bool _has_rhyming_adverb = false;
37 bool _has_rhyming_verb = false;
30 }; 38 };
31 39
32}; 40};
diff --git a/lib/word.cpp b/lib/word.cpp index 13c611f..49e34a1 100644 --- a/lib/word.cpp +++ b/lib/word.cpp
@@ -3,6 +3,26 @@
3 3
4namespace verbly { 4namespace verbly {
5 5
6 rhyme::rhyme(std::string prerhyme, std::string phonemes) : _prerhyme(prerhyme), _rhyme(phonemes)
7 {
8
9 }
10
11 std::string rhyme::get_prerhyme() const
12 {
13 return _prerhyme;
14 }
15
16 std::string rhyme::get_rhyme() const
17 {
18 return _rhyme;
19 }
20
21 bool rhyme::operator==(const rhyme& other) const
22 {
23 return std::tie(_prerhyme, _rhyme) == std::tie(other._prerhyme, other._rhyme);
24 }
25
6 word::word() 26 word::word()
7 { 27 {
8 28
@@ -13,28 +33,11 @@ namespace verbly {
13 33
14 } 34 }
15 35
16 std::list<std::string> word::rhyme_phonemes() const 36 std::list<rhyme> word::get_rhymes() const
17 { 37 {
18 assert(_valid == true); 38 assert(_valid == true);
19 39
20 std::list<std::string> result; 40 return rhymes;
21
22 for (auto pronunciation : pronunciations)
23 {
24 auto phemstrt = std::find_if(std::begin(pronunciation), std::end(pronunciation), [] (std::string phoneme) {
25 return phoneme.find("1") != std::string::npos;
26 });
27
28 std::stringstream rhymer;
29 for (auto it = phemstrt; it != std::end(pronunciation); it++)
30 {
31 rhymer << " " << *it;
32 }
33
34 result.push_back(rhymer.str());
35 }
36
37 return result;
38 } 41 }
39 42
40 bool word::starts_with_vowel_sound() const 43 bool word::starts_with_vowel_sound() const
diff --git a/lib/word.h b/lib/word.h index dc6fac8..08797a3 100644 --- a/lib/word.h +++ b/lib/word.h
@@ -3,6 +3,20 @@
3 3
4namespace verbly { 4namespace verbly {
5 5
6 class rhyme {
7 public:
8 rhyme(std::string prerhyme, std::string phonemes);
9
10 std::string get_prerhyme() const;
11 std::string get_rhyme() const;
12
13 bool operator==(const rhyme& other) const;
14
15 private:
16 std::string _prerhyme;
17 std::string _rhyme;
18 };
19
6 class word { 20 class word {
7 protected: 21 protected:
8 const data* _data; 22 const data* _data;
@@ -10,6 +24,7 @@ namespace verbly {
10 bool _valid = false; 24 bool _valid = false;
11 25
12 std::list<std::list<std::string>> pronunciations; 26 std::list<std::list<std::string>> pronunciations;
27 std::list<rhyme> rhymes;
13 28
14 word(); 29 word();
15 word(const data& _data, int _id); 30 word(const data& _data, int _id);
@@ -24,7 +39,7 @@ namespace verbly {
24 public: 39 public:
25 virtual std::string base_form() const = 0; 40 virtual std::string base_form() const = 0;
26 41
27 std::list<std::string> rhyme_phonemes() const; 42 std::list<rhyme> get_rhymes() const;
28 bool starts_with_vowel_sound() const; 43 bool starts_with_vowel_sound() const;
29 }; 44 };
30 45