From 040ee58fecdc9c478004bc2e554e1ae126ec4602 Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Fri, 15 Apr 2016 17:24:44 -0400 Subject: Added support for ImageNet and fixed bug with query interface Datafile change: nouns now know how many images are associated with them on ImageNet, and also have their WordNet synset ID saved so that you can query for images of that noun via the ImageNet API. So far, verbly only exposes the ImageNet API URL, and doesn't actually interact with it itself. This may be changed in the future. The query interface had a huge issue in which multiple instances of the same condition would overwrite each other. This has been fixed. --- lib/adjective_query.cpp | 147 +++++++++++--------------- lib/adverb_query.cpp | 103 +++++++++--------- lib/data.cpp | 117 +++++++++++++++++++++ lib/data.h | 32 ++++++ lib/frame_query.cpp | 30 +++++- lib/noun.cpp | 17 +++ lib/noun.h | 4 + lib/noun_query.cpp | 274 ++++++++++++++++++++++++------------------------ lib/noun_query.h | 6 ++ lib/preposition.cpp | 30 +++++- lib/verb_query.cpp | 39 ++++--- 11 files changed, 503 insertions(+), 296 deletions(-) (limited to 'lib') diff --git a/lib/adjective_query.cpp b/lib/adjective_query.cpp index 283fdca..a7f915c 100644 --- a/lib/adjective_query.cpp +++ b/lib/adjective_query.cpp @@ -218,6 +218,7 @@ namespace verbly { std::stringstream construct; construct << "SELECT adjective_id, base_form, comparative, superlative, position FROM adjectives"; std::list conditions; + std::list bindings; if (_has_prn) { @@ -226,14 +227,20 @@ namespace verbly { if (!_rhymes.empty()) { - std::list clauses(_rhymes.size(), "pronunciation LIKE @RHMPRN"); + std::list clauses(_rhymes.size(), "pronunciation LIKE ?"); std::string cond = "adjective_id IN (SELECT adjective_id FROM adjective_pronunciations WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; conditions.push_back(cond); + + for (auto rhyme : _rhymes) + { + bindings.emplace_back("%" + rhyme); + } } for (auto except : _except) { - conditions.push_back("adjective_id != @EXCID"); + conditions.push_back("adjective_id != ?"); + bindings.emplace_back(except._id); } if (_requires_comparative_form) @@ -261,11 +268,13 @@ namespace verbly { { case filter::type::singleton: { + bindings.emplace_back(f.get_elem() + "%"); + if (notlogic == f.get_notlogic()) { - return "base_form LIKE @PREFIX"; + return "base_form LIKE ?"; } else { - return "base_form NOT LIKE @PREFIX"; + return "base_form NOT LIKE ?"; } } @@ -298,11 +307,13 @@ namespace verbly { { case filter::type::singleton: { + bindings.emplace_back("%" + f.get_elem()); + if (notlogic == f.get_notlogic()) { - return "base_form LIKE @SUFFIX"; + return "base_form LIKE ?"; } else { - return "base_form NOT LIKE @SUFFIX"; + return "base_form NOT LIKE ?"; } } @@ -330,7 +341,8 @@ namespace verbly { if (_with_complexity != unlimited) { - conditions.push_back("complexity = @COMPLEX"); + conditions.push_back("complexity = ?"); + bindings.emplace_back(_with_complexity); } if (_is_variant) @@ -355,11 +367,13 @@ namespace verbly { { case filter::type::singleton: { + bindings.emplace_back(f.get_elem()._id); + if (notlogic == f.get_notlogic()) { - return "noun_id = @ATTRID"; + return "noun_id = ?"; } else { - return "noun_id != @ATTRID"; + return "noun_id != ?"; } } @@ -409,11 +423,13 @@ namespace verbly { { case filter::type::singleton: { + bindings.emplace_back(f.get_elem()._id); + if (notlogic == f.get_notlogic()) { - return "adjective_1_id = @ANTID"; + return "adjective_1_id = ?"; } else { - return "adjective_1_id != @ANTID"; + return "adjective_1_id != ?"; } } @@ -463,11 +479,13 @@ namespace verbly { { case filter::type::singleton: { + bindings.emplace_back(f.get_elem()._id); + if (notlogic == f.get_notlogic()) { - return "adjective_1_id = @SYNID"; + return "adjective_1_id = ?"; } else { - return "adjective_1_id != @SYNID"; + return "adjective_1_id != ?"; } } @@ -517,11 +535,13 @@ namespace verbly { { case filter::type::singleton: { + bindings.emplace_back(f.get_elem()._id); + if (notlogic == f.get_notlogic()) { - return "specific_id = @SPECID"; + return "specific_id = ?"; } else { - return "specific_id != @SPECID"; + return "specific_id != ?"; } } @@ -571,11 +591,13 @@ namespace verbly { { case filter::type::singleton: { + bindings.emplace_back(f.get_elem()._id); + if (notlogic == f.get_notlogic()) { - return "general_id = @GENID"; + return "general_id = ?"; } else { - return "general_id != @GENID"; + return "general_id != ?"; } } @@ -625,11 +647,13 @@ namespace verbly { { case filter::type::singleton: { + bindings.emplace_back(f.get_elem()._id); + if (notlogic == f.get_notlogic()) { - return "noun_id = @APERID"; + return "noun_id = ?"; } else { - return "noun_id != @APERID"; + return "noun_id != ?"; } } @@ -679,11 +703,13 @@ namespace verbly { { case filter::type::singleton: { + bindings.emplace_back(f.get_elem()._id); + if (notlogic == f.get_notlogic()) { - return "mannernym_id = @MANID"; + return "mannernym_id = ?"; } else { - return "mannernym_id != @MANID"; + return "mannernym_id != ?"; } } @@ -776,74 +802,29 @@ namespace verbly { throw std::runtime_error(sqlite3_errmsg(_data.ppdb)); } - if (!_rhymes.empty()) + int i = 1; + for (auto& binding : bindings) { - int i = 0; - for (auto rhyme : _rhymes) + switch (binding.get_type()) { - std::string rhymer = "%" + rhyme; - sqlite3_bind_text(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@RHMPRN"), rhymer.c_str(), rhymer.length(), SQLITE_STATIC); + case binding::type::integer: + { + sqlite3_bind_int(ppstmt, i, binding.get_integer()); + + break; + } - i++; + case binding::type::string: + { + sqlite3_bind_text(ppstmt, i, binding.get_string().c_str(), binding.get_string().length(), SQLITE_STATIC); + + break; + } } + + i++; } - for (auto except : _except) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@EXCID"), except._id); - } - - for (auto prefix : _with_prefix.inorder_flatten()) - { - std::string pfat = prefix + "%"; - sqlite3_bind_text(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@PREFIX"), pfat.c_str(), pfat.length(), SQLITE_STATIC); - } - - for (auto suffix : _with_suffix.inorder_flatten()) - { - std::string pfat = "%" + suffix; - sqlite3_bind_text(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@SUFFIX"), pfat.c_str(), pfat.length(), SQLITE_STATIC); - } - - if (_with_complexity != unlimited) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@COMPLEX"), _with_complexity); - } - - for (auto attribute : _variant_of.inorder_flatten()) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@ATTRID"), attribute._id); - } - - for (auto antonym : _antonym_of.inorder_flatten()) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@ANTID"), antonym._id); - } - - for (auto synonym : _synonym_of.inorder_flatten()) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@SYNID"), synonym._id); - } - - for (auto specific : _generalization_of.inorder_flatten()) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@SPECID"), specific._id); - } - - for (auto general : _specification_of.inorder_flatten()) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@GENID"), general._id); - } - - for (auto n : _pertainym_of.inorder_flatten()) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@APERID"), n._id); - } - - for (auto mannernym : _anti_mannernym_of.inorder_flatten()) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@MANID"), mannernym._id); - } /* for (auto adj : _derived_from_adjective) { diff --git a/lib/adverb_query.cpp b/lib/adverb_query.cpp index c9d0d09..30ba92b 100644 --- a/lib/adverb_query.cpp +++ b/lib/adverb_query.cpp @@ -172,6 +172,7 @@ namespace verbly { std::stringstream construct; construct << "SELECT adverb_id, base_form, comparative, superlative FROM adverbs"; std::list conditions; + std::list bindings; if (_has_prn) { @@ -180,14 +181,20 @@ namespace verbly { if (!_rhymes.empty()) { - std::list clauses(_rhymes.size(), "pronunciation LIKE @RHMPRN"); + std::list clauses(_rhymes.size(), "pronunciation LIKE ?"); std::string cond = "adverb_id IN (SELECT adverb_id FROM adverb_pronunciations WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; conditions.push_back(cond); + + for (auto rhyme : _rhymes) + { + bindings.emplace_back("%" + rhyme); + } } for (auto except : _except) { - conditions.push_back("adverb_id != @EXCID"); + conditions.push_back("adverb_id != ?"); + bindings.emplace_back(except._id); } if (_requires_comparative_form) @@ -207,11 +214,13 @@ namespace verbly { { case filter::type::singleton: { + bindings.emplace_back(f.get_elem() + "%"); + if (notlogic == f.get_notlogic()) { - return "base_form LIKE @PREFIX"; + return "base_form LIKE ?"; } else { - return "base_form NOT LIKE @PREFIX"; + return "base_form NOT LIKE ?"; } } @@ -244,11 +253,13 @@ namespace verbly { { case filter::type::singleton: { + bindings.emplace_back("%" + f.get_elem()); + if (notlogic == f.get_notlogic()) { - return "base_form LIKE @SUFFIX"; + return "base_form LIKE ?"; } else { - return "base_form NOT LIKE @SUFFIX"; + return "base_form NOT LIKE ?"; } } @@ -276,7 +287,8 @@ namespace verbly { if (_with_complexity != unlimited) { - conditions.push_back("complexity = @COMPLEX"); + conditions.push_back("complexity = ?"); + bindings.emplace_back(_with_complexity); } if (_has_antonyms) @@ -301,11 +313,13 @@ namespace verbly { { case filter::type::singleton: { + bindings.emplace_back(f.get_elem()._id); + if (notlogic == f.get_notlogic()) { - return "adverb_1_id = @ANTID"; + return "adverb_1_id = ?"; } else { - return "adverb_1_id != @ANTID"; + return "adverb_1_id != ?"; } } @@ -355,11 +369,13 @@ namespace verbly { { case filter::type::singleton: { + bindings.emplace_back(f.get_elem()._id); + if (notlogic == f.get_notlogic()) { - return "adverb_1_id = @SYNID"; + return "adverb_1_id = ?"; } else { - return "adverb_1_id != @SYNID"; + return "adverb_1_id != ?"; } } @@ -409,11 +425,13 @@ namespace verbly { { case filter::type::singleton: { + bindings.emplace_back(f.get_elem()._id); + if (notlogic == f.get_notlogic()) { - return "adjective_id = @AMANID"; + return "adjective_id = ?"; } else { - return "adjective_id != @AMANID"; + return "adjective_id != ?"; } } @@ -506,54 +524,29 @@ namespace verbly { throw std::runtime_error(sqlite3_errmsg(_data.ppdb)); } - if (!_rhymes.empty()) + int i = 1; + for (auto& binding : bindings) { - int i = 0; - for (auto rhyme : _rhymes) + switch (binding.get_type()) { - std::string rhymer = "%" + rhyme; - sqlite3_bind_text(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@RHMPRN"), rhymer.c_str(), rhymer.length(), SQLITE_STATIC); + case binding::type::integer: + { + sqlite3_bind_int(ppstmt, i, binding.get_integer()); + + break; + } - i++; + case binding::type::string: + { + sqlite3_bind_text(ppstmt, i, binding.get_string().c_str(), binding.get_string().length(), SQLITE_STATIC); + + break; + } } + + i++; } - for (auto except : _except) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@EXCID"), except._id); - } - - for (auto prefix : _with_prefix.inorder_flatten()) - { - std::string pfat = prefix + "%"; - sqlite3_bind_text(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@PREFIX"), pfat.c_str(), pfat.length(), SQLITE_STATIC); - } - - for (auto suffix : _with_suffix.inorder_flatten()) - { - std::string pfat = "%" + suffix; - sqlite3_bind_text(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@SUFFIX"), pfat.c_str(), pfat.length(), SQLITE_STATIC); - } - - if (_with_complexity != unlimited) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@COMPLEX"), _with_complexity); - } - - for (auto antonym : _antonym_of.inorder_flatten()) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@ANTID"), antonym._id); - } - - for (auto synonym : _synonym_of.inorder_flatten()) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@SYNID"), synonym._id); - } - - for (auto adj : _mannernym_of.inorder_flatten()) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@AMANID"), adj._id); - } /* for (auto adj : _derived_from_adjective) { diff --git a/lib/data.cpp b/lib/data.cpp index 5a9397b..c14956f 100644 --- a/lib/data.cpp +++ b/lib/data.cpp @@ -57,4 +57,121 @@ namespace verbly { return preposition_query(*this); } + binding::type binding::get_type() const + { + return _type; + } + + binding::binding(const binding& other) + { + _type = other._type; + + switch (_type) + { + case type::integer: + { + _integer = other._integer; + + break; + } + + case type::string: + { + new(&_string) std::string(other._string); + + break; + } + } + } + + binding::~binding() + { + switch (_type) + { + case type::string: + { + using string_type = std::string; + _string.~string_type(); + + break; + } + } + } + + binding& binding::operator=(const binding& other) + { + this->~binding(); + + _type = other._type; + + switch (_type) + { + case type::integer: + { + _integer = other._integer; + + break; + } + + case type::string: + { + new(&_string) std::string(other._string); + + break; + } + } + + return *this; + } + + binding::binding(int _arg) + { + _type = type::integer; + _integer = _arg; + } + + int binding::get_integer() const + { + assert(_type == type::integer); + + return _integer; + } + + void binding::set_integer(int _arg) + { + *this = binding(_arg); + } + + binding& binding::operator=(int _arg) + { + *this = binding(_arg); + + return *this; + } + + binding::binding(std::string _arg) + { + _type = type::string; + new(&_string) std::string(_arg); + } + + std::string binding::get_string() const + { + assert(_type == type::string); + + return _string; + } + + void binding::set_string(std::string _arg) + { + *this = binding(_arg); + } + + binding& binding::operator=(std::string _arg) + { + *this = binding(_arg); + + return *this; + } + }; diff --git a/lib/data.h b/lib/data.h index 0d599c4..b8b12b9 100644 --- a/lib/data.h +++ b/lib/data.h @@ -343,6 +343,38 @@ namespace verbly { }; }; + class binding { + public: + enum class type { + integer, + string + }; + + type get_type() const; + binding(const binding& other); + ~binding(); + binding& operator=(const binding& other); + + // Integer + binding(int _arg); + int get_integer() const; + void set_integer(int _arg); + binding& operator=(int _arg); + + // String + binding(std::string _arg); + std::string get_string() const; + void set_string(std::string _arg); + binding& operator=(std::string _arg); + + private: + union { + int _integer; + std::string _string; + }; + type _type; + }; + }; #endif /* end of include guard: DATA_H_C4AEC3DD */ diff --git a/lib/frame_query.cpp b/lib/frame_query.cpp index 6583da4..3c4a3e8 100644 --- a/lib/frame_query.cpp +++ b/lib/frame_query.cpp @@ -37,13 +37,19 @@ namespace verbly { { std::stringstream construct; construct << "SELECT frames.data, groups.data FROM frames INNER JOIN groups ON frames.group_id = groups.group_id"; + std::list bindings; if (!_for_verb.empty()) { - std::list clauses(_for_verb.size(), "verb_id = @VERID"); + std::list clauses(_for_verb.size(), "verb_id = ?"); construct << " WHERE frames.group_id IN (SELECT group_id FROM verb_groups WHERE "; construct << verbly::implode(std::begin(clauses), std::end(clauses), " OR "); construct << ")"; + + for (auto v : _for_verb) + { + bindings.emplace_back(v._id); + } } sqlite3_stmt* ppstmt; @@ -53,9 +59,27 @@ namespace verbly { throw std::runtime_error(sqlite3_errmsg(_data.ppdb)); } - for (auto verb : _for_verb) + int i = 1; + for (auto& binding : bindings) { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@VERID"), verb._id); + switch (binding.get_type()) + { + case binding::type::integer: + { + sqlite3_bind_int(ppstmt, i, binding.get_integer()); + + break; + } + + case binding::type::string: + { + sqlite3_bind_text(ppstmt, i, binding.get_string().c_str(), binding.get_string().length(), SQLITE_STATIC); + + break; + } + } + + i++; } std::list output; diff --git a/lib/noun.cpp b/lib/noun.cpp index 71c9af0..d8b34c9 100644 --- a/lib/noun.cpp +++ b/lib/noun.cpp @@ -34,6 +34,13 @@ namespace verbly { return _plural; } + + int noun::wnid() const + { + assert(_valid == true); + + return _wnid; + } bool noun::has_plural_form() const { @@ -196,6 +203,16 @@ namespace verbly { return _data->adjectives().variant_of(*this); } + std::string noun::imagenet_url() const + { + std::stringstream url; + url << "http://www.image-net.org/api/text/imagenet.synset.geturls?wnid=n"; + url.width(8); + url.fill('0'); + url << (_wnid % 100000000); + return url.str(); + } + bool noun::operator<(const noun& other) const { return _id < other._id; diff --git a/lib/noun.h b/lib/noun.h index 969d2c8..bd71e57 100644 --- a/lib/noun.h +++ b/lib/noun.h @@ -7,6 +7,7 @@ namespace verbly { private: std::string _singular; std::string _plural; + int _wnid; friend class noun_query; @@ -17,6 +18,7 @@ namespace verbly { std::string base_form() const; std::string singular_form() const; std::string plural_form() const; + int wnid() const; bool has_plural_form() const; @@ -43,6 +45,8 @@ namespace verbly { adjective_query pertainyms() const; adjective_query variations() const; + std::string imagenet_url() const; + bool operator<(const noun& other) const; }; diff --git a/lib/noun_query.cpp b/lib/noun_query.cpp index 83bb47d..19a1297 100644 --- a/lib/noun_query.cpp +++ b/lib/noun_query.cpp @@ -370,6 +370,21 @@ namespace verbly { return *this; } + + noun_query& noun_query::at_least_n_images(int _arg) + { + _at_least_n_images = _arg; + + return *this; + } + + noun_query& noun_query::with_wnid(int _arg) + { + _with_wnid.insert(_arg); + + return *this; + } + /* noun_query& noun_query::derived_from(const word& _w) { @@ -457,8 +472,9 @@ namespace verbly { construct << " "; } - construct << "SELECT noun_id, singular, plural FROM nouns"; + construct << "SELECT noun_id, singular, plural, wnid FROM nouns"; std::list conditions; + std::list bindings; if (_has_prn) { @@ -467,21 +483,32 @@ namespace verbly { if (!_rhymes.empty()) { - std::list clauses(_rhymes.size(), "pronunciation LIKE @RHMPRN"); + std::list clauses(_rhymes.size(), "pronunciation LIKE ?"); std::string cond = "noun_id IN (SELECT noun_id FROM noun_pronunciations WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; conditions.push_back(cond); + + for (auto rhyme : _rhymes) + { + bindings.emplace_back("%" + rhyme); + } } for (auto except : _except) { - conditions.push_back("noun_id != @EXCID"); + conditions.push_back("noun_id != ?"); + bindings.emplace_back(except._id); } if (!_with_singular_form.empty()) { - std::list clauses(_with_singular_form.size(), "singular = @SFORM"); + std::list clauses(_with_singular_form.size(), "singular = ?"); std::string cond = "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; conditions.push_back(cond); + + for (auto form : _with_singular_form) + { + bindings.emplace_back(form); + } } if (!_with_prefix.empty()) @@ -491,11 +518,13 @@ namespace verbly { { case filter::type::singleton: { + bindings.emplace_back(f.get_elem() + "%"); + if (notlogic == f.get_notlogic()) { - return "singular LIKE @PREFIX"; + return "singular LIKE ?"; } else { - return "singular NOT LIKE @PREFIX"; + return "singular NOT LIKE ?"; } } @@ -528,11 +557,13 @@ namespace verbly { { case filter::type::singleton: { + bindings.emplace_back("%" + f.get_elem()); + if (notlogic == f.get_notlogic()) { - return "singular LIKE @SUFFIX"; + return "singular LIKE ?"; } else { - return "singular NOT LIKE @SUFFIX"; + return "singular NOT LIKE ?"; } } @@ -560,7 +591,8 @@ namespace verbly { if (_with_complexity != unlimited) { - conditions.push_back("complexity = @COMPLEX"); + conditions.push_back("complexity = ?"); + bindings.emplace_back(_with_complexity); } if (_is_hypernym) @@ -585,11 +617,13 @@ namespace verbly { { case filter::type::singleton: { + bindings.emplace_back(f.get_elem()._id); + if (notlogic == f.get_notlogic()) { - return "hyponym_id = @HYPO"; + return "hyponym_id = ?"; } else { - return "hyponym_id != @HYPO"; + return "hyponym_id != ?"; } } @@ -713,11 +747,13 @@ namespace verbly { { case filter::type::singleton: { + bindings.emplace_back(f.get_elem()._id); + if (notlogic == f.get_notlogic()) { - return "hypernym_id = @HYPER"; + return "hypernym_id = ?"; } else { - return "hypernym_id != @HYPER"; + return "hypernym_id != ?"; } } @@ -767,11 +803,13 @@ namespace verbly { { case filter::type::singleton: { + bindings.emplace_back(f.get_elem()._id); + if (notlogic == f.get_notlogic()) { - return "holonym_id = @PHOLO"; + return "holonym_id = ?"; } else { - return "holonym_id != @PHOLO"; + return "holonym_id != ?"; } } @@ -858,11 +896,13 @@ namespace verbly { { case filter::type::singleton: { + bindings.emplace_back(f.get_elem()._id); + if (notlogic == f.get_notlogic()) { - return "meronym_id = @PMERO"; + return "meronym_id = ?"; } else { - return "meronym_id != @PMERO"; + return "meronym_id != ?"; } } @@ -949,11 +989,13 @@ namespace verbly { { case filter::type::singleton: { + bindings.emplace_back(f.get_elem()._id); + if (notlogic == f.get_notlogic()) { - return "holonym_id = @SHOLO"; + return "holonym_id = ?"; } else { - return "holonym_id != @SHOLO"; + return "holonym_id != ?"; } } @@ -1040,11 +1082,13 @@ namespace verbly { { case filter::type::singleton: { + bindings.emplace_back(f.get_elem()._id); + if (notlogic == f.get_notlogic()) { - return "meronym_id = @SMERO"; + return "meronym_id = ?"; } else { - return "meronym_id != @SMERO"; + return "meronym_id != ?"; } } @@ -1131,11 +1175,13 @@ namespace verbly { { case filter::type::singleton: { + bindings.emplace_back(f.get_elem()._id); + if (notlogic == f.get_notlogic()) { - return "holonym_id = @MHOLO"; + return "holonym_id = ?"; } else { - return "holonym_id != @MHOLO"; + return "holonym_id != ?"; } } @@ -1222,11 +1268,13 @@ namespace verbly { { case filter::type::singleton: { + bindings.emplace_back(f.get_elem()._id); + if (notlogic == f.get_notlogic()) { - return "meronym_id = @MMERO"; + return "meronym_id = ?"; } else { - return "meronym_id != @MMERO"; + return "meronym_id != ?"; } } @@ -1323,11 +1371,13 @@ namespace verbly { { case filter::type::singleton: { + bindings.emplace_back(f.get_elem()._id); + if (notlogic == f.get_notlogic()) { - return "class_id = @CLSID"; + return "class_id = ?"; } else { - return "class_id != @CLSID"; + return "class_id != ?"; } } @@ -1377,11 +1427,13 @@ namespace verbly { { case filter::type::singleton: { + bindings.emplace_back(f.get_elem()._id); + if (notlogic == f.get_notlogic()) { - return "instance_id = @INSID"; + return "instance_id = ?"; } else { - return "instance_id != @INSID"; + return "instance_id != ?"; } } @@ -1431,11 +1483,13 @@ namespace verbly { { case filter::type::singleton: { + bindings.emplace_back(f.get_elem()._id); + if (notlogic == f.get_notlogic()) { - return "noun_1_id = @SYNID"; + return "noun_1_id = ?"; } else { - return "noun_1_id != @SYNID"; + return "noun_1_id != ?"; } } @@ -1485,11 +1539,13 @@ namespace verbly { { case filter::type::singleton: { + bindings.emplace_back(f.get_elem()._id); + if (notlogic == f.get_notlogic()) { - return "noun_1_id = @ANTID"; + return "noun_1_id = ?"; } else { - return "noun_1_id != @ANTID"; + return "noun_1_id != ?"; } } @@ -1539,11 +1595,13 @@ namespace verbly { { case filter::type::singleton: { + bindings.emplace_back(f.get_elem()._id); + if (notlogic == f.get_notlogic()) { - return "pertainym_id = @PERID"; + return "pertainym_id = ?"; } else { - return "pertainym_id != @PERID"; + return "pertainym_id != ?"; } } @@ -1593,11 +1651,13 @@ namespace verbly { { case filter::type::singleton: { + bindings.emplace_back(f.get_elem()._id); + if (notlogic == f.get_notlogic()) { - return "adjective_id = @VALID"; + return "adjective_id = ?"; } else { - return "adjective_id != @VALID"; + return "adjective_id != ?"; } } @@ -1624,6 +1684,25 @@ namespace verbly { cond << ")"; conditions.push_back(cond.str()); } + + if (_at_least_n_images != unlimited) + { + conditions.push_back("images >= ?"); + bindings.emplace_back(_at_least_n_images); + } + + if (!_with_wnid.empty()) + { + std::vector clauses(_with_wnid.size(), "wnid = ?"); + std::string cond = verbly::implode(std::begin(clauses), std::end(clauses), " OR "); + conditions.push_back("(" + cond + ")"); + + for (auto wnid : _with_wnid) + { + bindings.emplace_back(wnid); + } + } + /* if (!_derived_from_adjective.empty()) { @@ -1690,114 +1769,29 @@ namespace verbly { throw std::runtime_error(sqlite3_errmsg(_data.ppdb)); } - if (!_rhymes.empty()) + int i = 1; + for (auto& binding : bindings) { - int i = 0; - for (auto rhyme : _rhymes) + switch (binding.get_type()) { - std::string rhymer = "%" + rhyme; - sqlite3_bind_text(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@RHMPRN"), rhymer.c_str(), rhymer.length(), SQLITE_STATIC); + case binding::type::integer: + { + sqlite3_bind_int(ppstmt, i, binding.get_integer()); + + break; + } - i++; + case binding::type::string: + { + sqlite3_bind_text(ppstmt, i, binding.get_string().c_str(), binding.get_string().length(), SQLITE_STATIC); + + break; + } } + + i++; } - for (auto except : _except) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@EXCID"), except._id); - } - - for (auto sform : _with_singular_form) - { - sqlite3_bind_text(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@SFORM"), sform.c_str(), sform.size(), SQLITE_STATIC); - } - - for (auto prefix : _with_prefix.inorder_flatten()) - { - std::string pfat = prefix + "%"; - sqlite3_bind_text(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@PREFIX"), pfat.c_str(), pfat.length(), SQLITE_STATIC); - } - - for (auto suffix : _with_suffix.inorder_flatten()) - { - std::string pfat = "%" + suffix; - sqlite3_bind_text(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@SUFFIX"), pfat.c_str(), pfat.length(), SQLITE_STATIC); - } - - if (_with_complexity != unlimited) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@COMPLEX"), _with_complexity); - } - - for (auto hyponym : _hypernym_of.inorder_flatten()) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@HYPO"), hyponym._id); - } - - for (auto hypernym : _hyponym_of.inorder_flatten()) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@HYPER"), hypernym._id); - } - - for (auto holonym : _part_meronym_of.inorder_flatten()) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@PHOLO"), holonym._id); - } - - for (auto meronym : _part_holonym_of.inorder_flatten()) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@PMERO"), meronym._id); - } - - for (auto holonym : _substance_meronym_of.inorder_flatten()) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@SHOLO"), holonym._id); - } - - for (auto meronym : _substance_holonym_of.inorder_flatten()) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@SMERO"), meronym._id); - } - - for (auto holonym : _member_meronym_of.inorder_flatten()) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@MHOLO"), holonym._id); - } - - for (auto meronym : _member_holonym_of.inorder_flatten()) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@MMERO"), meronym._id); - } - - for (auto cls : _instance_of.inorder_flatten()) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@CLSID"), cls._id); - } - - for (auto inst : _class_of.inorder_flatten()) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@INSID"), inst._id); - } - - for (auto synonym : _synonym_of.inorder_flatten()) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@SYNID"), synonym._id); - } - - for (auto antonym : _antonym_of.inorder_flatten()) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@ANTID"), antonym._id); - } - - for (auto pertainym : _anti_pertainym_of.inorder_flatten()) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@PERID"), pertainym._id); - } - - for (auto value : _attribute_of.inorder_flatten()) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@VALID"), value._id); - } /* for (auto adj : _derived_from_adjective) { @@ -1839,6 +1833,8 @@ namespace verbly { { tnc._plural = std::string(reinterpret_cast(sqlite3_column_text(ppstmt, 2))); } + + tnc._wnid = sqlite3_column_int(ppstmt, 3); output.push_back(tnc); } diff --git a/lib/noun_query.h b/lib/noun_query.h index 5b73f8d..8768f5d 100644 --- a/lib/noun_query.h +++ b/lib/noun_query.h @@ -72,6 +72,9 @@ namespace verbly { noun_query& is_attribute(); noun_query& attribute_of(filter _f); + noun_query& at_least_n_images(int _arg); + noun_query& with_wnid(int _arg); + /* noun_query& derived_from(const word& _w); noun_query& not_derived_from(const word& _w);*/ @@ -146,6 +149,9 @@ namespace verbly { bool _is_attribute = false; filter _attribute_of; + int _at_least_n_images = unlimited; + std::set _with_wnid; + /* std::list _derived_from_adjective; std::list _not_derived_from_adjective; std::list _derived_from_adverb; diff --git a/lib/preposition.cpp b/lib/preposition.cpp index c619bbf..8df13aa 100644 --- a/lib/preposition.cpp +++ b/lib/preposition.cpp @@ -37,13 +37,19 @@ namespace verbly { { std::stringstream construct; construct << "SELECT form FROM prepositions"; + std::list bindings; if (!_in_group.empty()) { - std::list clauses(_in_group.size(), "groupname = @GNAME"); + std::list clauses(_in_group.size(), "groupname = ?"); construct << " WHERE preposition_id IN (SELECT preposition_id FROM preposition_groups WHERE "; construct << verbly::implode(std::begin(clauses), std::end(clauses), " OR "); construct << ")"; + + for (auto g : _in_group) + { + bindings.emplace_back(g); + } } if (_random) @@ -63,9 +69,27 @@ namespace verbly { throw std::runtime_error(sqlite3_errmsg(_data.ppdb)); } - for (auto& group : _in_group) + int i = 1; + for (auto& binding : bindings) { - sqlite3_bind_text(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@GNAME"), group.c_str(), group.length(), SQLITE_STATIC); + switch (binding.get_type()) + { + case binding::type::integer: + { + sqlite3_bind_int(ppstmt, i, binding.get_integer()); + + break; + } + + case binding::type::string: + { + sqlite3_bind_text(ppstmt, i, binding.get_string().c_str(), binding.get_string().length(), SQLITE_STATIC); + + break; + } + } + + i++; } std::list output; diff --git a/lib/verb_query.cpp b/lib/verb_query.cpp index 173a04e..929ecc7 100644 --- a/lib/verb_query.cpp +++ b/lib/verb_query.cpp @@ -65,6 +65,7 @@ namespace verbly { std::stringstream construct; construct << "SELECT verb_id, infinitive, past_tense, past_participle, ing_form, s_form FROM verbs"; std::list conditions; + std::list bindings; if (_has_prn) { @@ -73,14 +74,20 @@ namespace verbly { if (!_rhymes.empty()) { - std::list clauses(_rhymes.size(), "pronunciation LIKE @RHMPRN"); + std::list clauses(_rhymes.size(), "pronunciation LIKE ?"); std::string cond = "verb_id IN (SELECT verb_id FROM verb_pronunciations WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; conditions.push_back(cond); + + for (auto rhyme : _rhymes) + { + bindings.emplace_back("%" + rhyme); + } } for (auto except : _except) { - conditions.push_back("verb_id != @EXCID"); + conditions.push_back("verb_id != ?"); + bindings.emplace_back(except._id); } if (!_has_frames) @@ -111,21 +118,27 @@ namespace verbly { throw std::runtime_error(sqlite3_errmsg(_data.ppdb)); } - if (!_rhymes.empty()) + int i = 1; + for (auto& binding : bindings) { - int i = 0; - for (auto rhyme : _rhymes) + switch (binding.get_type()) { - std::string rhymer = "%" + rhyme; - sqlite3_bind_text(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@RHMPRN"), rhymer.c_str(), rhymer.length(), SQLITE_STATIC); + case binding::type::integer: + { + sqlite3_bind_int(ppstmt, i, binding.get_integer()); + + break; + } - i++; + case binding::type::string: + { + sqlite3_bind_text(ppstmt, i, binding.get_string().c_str(), binding.get_string().length(), SQLITE_STATIC); + + break; + } } - } - - for (auto except : _except) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@EXCID"), except._id); + + i++; } std::list output; -- cgit 1.4.1 From 04338f2b040fee5142904c062e0e38c836601034 Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Sun, 17 Apr 2016 13:44:37 -0400 Subject: 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. --- generator/generator.cpp | 128 +++++++++++++++++++++++++++++++++++++++--------- generator/schema.sql | 8 +++ lib/adjective_query.cpp | 68 ++++++++++++++++++++++--- lib/adjective_query.h | 10 +++- lib/adverb_query.cpp | 68 ++++++++++++++++++++++--- lib/adverb_query.h | 10 +++- lib/data.cpp | 2 +- lib/frame_query.cpp | 2 +- lib/noun_query.cpp | 73 ++++++++++++++++++++++++--- lib/noun_query.h | 10 +++- lib/preposition.cpp | 2 +- lib/verb_query.cpp | 68 ++++++++++++++++++++++--- lib/verb_query.h | 10 +++- lib/word.cpp | 41 +++++++++------- lib/word.h | 17 ++++++- 15 files changed, 442 insertions(+), 75 deletions(-) (limited to 'lib') 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 { std::list> frames; }; +struct pronunciation_t { + std::string phonemes; + std::string prerhyme; + std::string rhyme; + + bool operator<(const pronunciation_t& other) const + { + return phonemes < other.phonemes; + } +}; + std::map groups; std::map verbs; std::map adjectives; std::map nouns; std::map> wn; std::map images; -std::map> pronunciations; +std::map> pronunciations; void print_usage() { @@ -590,7 +601,47 @@ int main(int argc, char** argv) std::string canonical(phoneme_data[1]); std::transform(std::begin(canonical), std::end(canonical), std::begin(canonical), ::tolower); - pronunciations[canonical].insert(phoneme_data[2]); + std::string phonemes = phoneme_data[2]; + auto phoneme_set = verbly::split>(phonemes, " "); + auto phemstrt = std::find_if(std::begin(phoneme_set), std::end(phoneme_set), [] (std::string phoneme) { + return phoneme.find("1") != std::string::npos; + }); + + pronunciation_t p; + p.phonemes = phonemes; + if (phemstrt != std::end(phoneme_set)) + { + std::stringstream rhymer; + for (auto it = phemstrt; it != std::end(phoneme_set); it++) + { + std::string naked; + std::remove_copy_if(std::begin(*it), std::end(*it), std::back_inserter(naked), [] (char ch) { + return isdigit(ch); + }); + + if (it != phemstrt) + { + rhymer << " "; + } + + rhymer << naked; + } + + p.rhyme = rhymer.str(); + + if (phemstrt != std::begin(phoneme_set)) + { + phemstrt--; + p.prerhyme = *phemstrt; + } else { + p.prerhyme = ""; + } + } else { + p.prerhyme = ""; + p.rhyme = ""; + } + + pronunciations[canonical].insert(p); } } @@ -720,7 +771,7 @@ int main(int argc, char** argv) db_error(ppdb, query); } - sqlite3_bind_text(ppstmt, 1, prep.c_str(), prep.length(), SQLITE_STATIC); + sqlite3_bind_text(ppstmt, 1, prep.c_str(), prep.length(), SQLITE_TRANSIENT); if (sqlite3_step(ppstmt) != SQLITE_DONE) { @@ -752,7 +803,7 @@ int main(int argc, char** argv) } sqlite3_bind_int(ppstmt, 1, rowid); - sqlite3_bind_text(ppstmt, 2, group.c_str(), group.length(), SQLITE_STATIC); + sqlite3_bind_text(ppstmt, 2, group.c_str(), group.length(), SQLITE_TRANSIENT); if (sqlite3_step(ppstmt) != SQLITE_DONE) { @@ -775,11 +826,11 @@ int main(int argc, char** argv) db_error(ppdb, query); } - sqlite3_bind_text(ppstmt, 1, mapping.second.infinitive.c_str(), mapping.second.infinitive.length(), SQLITE_STATIC); - sqlite3_bind_text(ppstmt, 2, mapping.second.past_tense.c_str(), mapping.second.past_tense.length(), SQLITE_STATIC); - sqlite3_bind_text(ppstmt, 3, mapping.second.past_participle.c_str(), mapping.second.past_participle.length(), SQLITE_STATIC); - sqlite3_bind_text(ppstmt, 4, mapping.second.ing_form.c_str(), mapping.second.ing_form.length(), SQLITE_STATIC); - sqlite3_bind_text(ppstmt, 5, mapping.second.s_form.c_str(), mapping.second.s_form.length(), SQLITE_STATIC); + sqlite3_bind_text(ppstmt, 1, mapping.second.infinitive.c_str(), mapping.second.infinitive.length(), SQLITE_TRANSIENT); + sqlite3_bind_text(ppstmt, 2, mapping.second.past_tense.c_str(), mapping.second.past_tense.length(), SQLITE_TRANSIENT); + sqlite3_bind_text(ppstmt, 3, mapping.second.past_participle.c_str(), mapping.second.past_participle.length(), SQLITE_TRANSIENT); + sqlite3_bind_text(ppstmt, 4, mapping.second.ing_form.c_str(), mapping.second.ing_form.length(), SQLITE_TRANSIENT); + sqlite3_bind_text(ppstmt, 5, mapping.second.s_form.c_str(), mapping.second.s_form.length(), SQLITE_TRANSIENT); if (sqlite3_step(ppstmt) != SQLITE_DONE) { @@ -811,14 +862,26 @@ int main(int argc, char** argv) for (auto pronunciation : pronunciations[canonical]) { - query = "INSERT INTO verb_pronunciations (verb_id, pronunciation) VALUES (?, ?)"; + if (!pronunciation.rhyme.empty()) + { + query = "INSERT INTO verb_pronunciations (verb_id, pronunciation, prerhyme, rhyme) VALUES (?, ?, ?, ?)"; + } else { + query = "INSERT INTO verb_pronunciations (verb_id, pronunciation) VALUES (?, ?)"; + } + if (sqlite3_prepare_v2(ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK) { db_error(ppdb, query); } sqlite3_bind_int(ppstmt, 1, rowid); - sqlite3_bind_text(ppstmt, 2, pronunciation.c_str(), pronunciation.length(), SQLITE_STATIC); + sqlite3_bind_text(ppstmt, 2, pronunciation.phonemes.c_str(), pronunciation.phonemes.length(), SQLITE_TRANSIENT); + + if (!pronunciation.rhyme.empty()) + { + sqlite3_bind_text(ppstmt, 3, pronunciation.prerhyme.c_str(), pronunciation.prerhyme.length(), SQLITE_TRANSIENT); + sqlite3_bind_text(ppstmt, 4, pronunciation.rhyme.c_str(), pronunciation.rhyme.length(), SQLITE_TRANSIENT); + } if (sqlite3_step(ppstmt) != SQLITE_DONE) { @@ -856,7 +919,7 @@ int main(int argc, char** argv) db_error(ppdb, query); } - sqlite3_bind_blob(ppstmt, 1, rdm.c_str(), rdm.size(), SQLITE_STATIC); + sqlite3_bind_blob(ppstmt, 1, rdm.c_str(), rdm.size(), SQLITE_TRANSIENT); if (sqlite3_step(ppstmt) != SQLITE_DONE) { @@ -949,7 +1012,7 @@ int main(int argc, char** argv) } sqlite3_bind_int(ppstmt, 1, gid); - sqlite3_bind_blob(ppstmt, 2, marshall.c_str(), marshall.length(), SQLITE_STATIC); + sqlite3_bind_blob(ppstmt, 2, marshall.c_str(), marshall.length(), SQLITE_TRANSIENT); if (sqlite3_step(ppstmt) != SQLITE_DONE) { @@ -1104,7 +1167,7 @@ int main(int argc, char** argv) db_error(ppdb, query); } - sqlite3_bind_text(ppstmt, 1, word.c_str(), word.length(), SQLITE_STATIC); + sqlite3_bind_text(ppstmt, 1, word.c_str(), word.length(), SQLITE_TRANSIENT); switch (synset_id / 100000000) { case 1: // Noun @@ -1119,7 +1182,7 @@ int main(int argc, char** argv) if (nouns.count(word) == 1) { - sqlite3_bind_text(ppstmt, 6, nouns[word].plural.c_str(), nouns[word].plural.length(), SQLITE_STATIC); + sqlite3_bind_text(ppstmt, 6, nouns[word].plural.c_str(), nouns[word].plural.length(), SQLITE_TRANSIENT); } break; @@ -1132,8 +1195,8 @@ int main(int argc, char** argv) if (adjectives.count(word) == 1) { - sqlite3_bind_text(ppstmt, 3, adjectives[word].comparative.c_str(), adjectives[word].comparative.length(), SQLITE_STATIC); - sqlite3_bind_text(ppstmt, 4, adjectives[word].superlative.c_str(), adjectives[word].superlative.length(), SQLITE_STATIC); + sqlite3_bind_text(ppstmt, 3, adjectives[word].comparative.c_str(), adjectives[word].comparative.length(), SQLITE_TRANSIENT); + sqlite3_bind_text(ppstmt, 4, adjectives[word].superlative.c_str(), adjectives[word].superlative.length(), SQLITE_TRANSIENT); } break; @@ -1173,21 +1236,36 @@ int main(int argc, char** argv) { case 1: // Noun { - query = "INSERT INTO noun_pronunciations (noun_id, pronunciation) VALUES (?, ?)"; + if (!pronunciation.rhyme.empty()) + { + query = "INSERT INTO noun_pronunciations (noun_id, pronunciation, prerhyme, rhyme) VALUES (?, ?, ?, ?)"; + } else { + query = "INSERT INTO noun_pronunciations (noun_id, pronunciation) VALUES (?, ?)"; + } break; } case 3: // Adjective { - query = "INSERT INTO adjective_pronunciations (adjective_id, pronunciation) VALUES (?, ?)"; + if (!pronunciation.rhyme.empty()) + { + query = "INSERT INTO adjective_pronunciations (adjective_id, pronunciation, prerhyme, rhyme) VALUES (?, ?, ?, ?)"; + } else { + query = "INSERT INTO adjective_pronunciations (adjective_id, pronunciation) VALUES (?, ?)"; + } break; } case 4: // Adverb { - query = "INSERT INTO adverb_pronunciations (adverb_id, pronunciation) VALUES (?, ?)"; + if (!pronunciation.rhyme.empty()) + { + query = "INSERT INTO adverb_pronunciations (adverb_id, pronunciation, prerhyme, rhyme) VALUES (?, ?, ?, ?)"; + } else { + query = "INSERT INTO adverb_pronunciations (adverb_id, pronunciation) VALUES (?, ?)"; + } break; } @@ -1199,7 +1277,13 @@ int main(int argc, char** argv) } sqlite3_bind_int(ppstmt, 1, rowid); - sqlite3_bind_text(ppstmt, 2, pronunciation.c_str(), pronunciation.length(), SQLITE_STATIC); + sqlite3_bind_text(ppstmt, 2, pronunciation.phonemes.c_str(), pronunciation.phonemes.length(), SQLITE_TRANSIENT); + + if (!pronunciation.rhyme.empty()) + { + sqlite3_bind_text(ppstmt, 3, pronunciation.prerhyme.c_str(), pronunciation.prerhyme.length(), SQLITE_TRANSIENT); + sqlite3_bind_text(ppstmt, 4, pronunciation.rhyme.c_str(), pronunciation.rhyme.length(), SQLITE_TRANSIENT); + } if (sqlite3_step(ppstmt) != SQLITE_DONE) { @@ -2188,7 +2272,7 @@ int main(int argc, char** argv) db_error(ppdb, query); } - sqlite3_bind_text(ppstmt, 1, syn.c_str(), 1, SQLITE_STATIC); + sqlite3_bind_text(ppstmt, 1, syn.c_str(), 1, SQLITE_TRANSIENT); sqlite3_bind_int(ppstmt, 2, wn[synset_id][wnum]); 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`; CREATE TABLE `noun_pronunciations` ( `noun_id` INTEGER NOT NULL, `pronunciation` VARCHAR(64) NOT NULL, + `prerhyme` VARCHAR(8), + `rhyme` VARCHAR(64), FOREIGN KEY (`noun_id`) REFERENCES `nouns`(`noun_id`) ); @@ -191,6 +193,8 @@ DROP TABLE IF EXISTS `verb_pronunciations`; CREATE TABLE `verb_pronunciations` ( `verb_id` INTEGER NOT NULL, `pronunciation` VARCHAR(64) NOT NULL, + `prerhyme` VARCHAR(8), + `rhyme` VARCHAR(64), FOREIGN KEY (`verb_id`) REFERENCES `verbs`(`verb_id`) ); @@ -198,6 +202,8 @@ DROP TABLE IF EXISTS `adjective_pronunciations`; CREATE TABLE `adjective_pronunciations` ( `adjective_id` INTEGER NOT NULL, `pronunciation` VARCHAR(64) NOT NULL, + `prerhyme` VARCHAR(8), + `rhyme` VARCHAR(64), FOREIGN KEY (`adjective_id`) REFERENCES `adjectives`(`adjective_id`) ); @@ -205,6 +211,8 @@ DROP TABLE IF EXISTS `adverb_pronunciations`; CREATE TABLE `adverb_pronunciations` ( `adverb_id` INTEGER NOT NULL, `pronunciation` VARCHAR(64) NOT NULL, + `prerhyme` VARCHAR(8), + `rhyme` VARCHAR(64), FOREIGN KEY (`adverb_id`) REFERENCES `adverbs`(`adverb_id`) ); 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 { adjective_query& adjective_query::rhymes_with(const word& _word) { - for (auto rhyme : _word.rhyme_phonemes()) + for (auto rhyme : _word.get_rhymes()) { _rhymes.push_back(rhyme); } @@ -53,6 +53,34 @@ namespace verbly { return *this; } + adjective_query& adjective_query::has_rhyming_noun() + { + _has_rhyming_noun = true; + + return *this; + } + + adjective_query& adjective_query::has_rhyming_adjective() + { + _has_rhyming_adjective = true; + + return *this; + } + + adjective_query& adjective_query::has_rhyming_adverb() + { + _has_rhyming_adverb = true; + + return *this; + } + + adjective_query& adjective_query::has_rhyming_verb() + { + _has_rhyming_verb = true; + + return *this; + } + adjective_query& adjective_query::with_prefix(filter _f) { _f.clean(); @@ -227,16 +255,37 @@ namespace verbly { if (!_rhymes.empty()) { - std::list clauses(_rhymes.size(), "pronunciation LIKE ?"); + std::list clauses(_rhymes.size(), "(prerhyme != ? AND rhyme = ?)"); std::string cond = "adjective_id IN (SELECT adjective_id FROM adjective_pronunciations WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; conditions.push_back(cond); - for (auto rhyme : _rhymes) + for (auto rhy : _rhymes) { - bindings.emplace_back("%" + rhyme); + bindings.emplace_back(rhy.get_prerhyme()); + bindings.emplace_back(rhy.get_rhyme()); } } + if (_has_rhyming_noun) + { + 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)"); + } + + if (_has_rhyming_adjective) + { + 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)"); + } + + if (_has_rhyming_adverb) + { + 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)"); + } + + if (_has_rhyming_verb) + { + 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)"); + } + for (auto except : _except) { conditions.push_back("adjective_id != ?"); @@ -816,7 +865,7 @@ namespace verbly { case binding::type::string: { - sqlite3_bind_text(ppstmt, i, binding.get_string().c_str(), binding.get_string().length(), SQLITE_STATIC); + sqlite3_bind_text(ppstmt, i, binding.get_string().c_str(), binding.get_string().length(), SQLITE_TRANSIENT); break; } @@ -894,7 +943,7 @@ namespace verbly { for (auto& adjective : output) { - query = "SELECT pronunciation FROM adjective_pronunciations WHERE adjective_id = ?"; + query = "SELECT pronunciation, prerhyme, rhyme FROM adjective_pronunciations WHERE adjective_id = ?"; if (sqlite3_prepare_v2(_data.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK) { throw std::runtime_error(sqlite3_errmsg(_data.ppdb)); @@ -908,6 +957,13 @@ namespace verbly { auto phonemes = verbly::split>(pronunciation, " "); adjective.pronunciations.push_back(phonemes); + + if ((sqlite3_column_type(ppstmt, 1) != SQLITE_NULL) && (sqlite3_column_type(ppstmt, 2) != SQLITE_NULL)) + { + std::string prerhyme(reinterpret_cast(sqlite3_column_text(ppstmt, 1))); + std::string rhyming(reinterpret_cast(sqlite3_column_text(ppstmt, 2))); + adjective.rhymes.emplace_back(prerhyme, rhyming); + } } 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 { adjective_query& except(const adjective& _word); adjective_query& rhymes_with(const word& _word); adjective_query& has_pronunciation(); + adjective_query& has_rhyming_noun(); + adjective_query& has_rhyming_adjective(); + adjective_query& has_rhyming_adverb(); + adjective_query& has_rhyming_verb(); adjective_query& requires_comparative_form(); adjective_query& requires_superlative_form(); @@ -54,9 +58,13 @@ namespace verbly { const data& _data; int _limit = unlimited; bool _random = false; - std::list _rhymes; + std::list _rhymes; std::list _except; bool _has_prn = false; + bool _has_rhyming_noun = false; + bool _has_rhyming_adjective = false; + bool _has_rhyming_adverb = false; + bool _has_rhyming_verb = false; bool _requires_comparative_form = false; 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 { adverb_query& adverb_query::rhymes_with(const word& _word) { - for (auto rhyme : _word.rhyme_phonemes()) + for (auto rhyme : _word.get_rhymes()) { _rhymes.push_back(rhyme); } @@ -53,6 +53,34 @@ namespace verbly { return *this; } + adverb_query& adverb_query::has_rhyming_noun() + { + _has_rhyming_noun = true; + + return *this; + } + + adverb_query& adverb_query::has_rhyming_adjective() + { + _has_rhyming_adjective = true; + + return *this; + } + + adverb_query& adverb_query::has_rhyming_adverb() + { + _has_rhyming_adverb = true; + + return *this; + } + + adverb_query& adverb_query::has_rhyming_verb() + { + _has_rhyming_verb = true; + + return *this; + } + adverb_query& adverb_query::requires_comparative_form() { _requires_comparative_form = true; @@ -181,16 +209,37 @@ namespace verbly { if (!_rhymes.empty()) { - std::list clauses(_rhymes.size(), "pronunciation LIKE ?"); + std::list clauses(_rhymes.size(), "(prerhyme != ? AND rhyme = ?)"); std::string cond = "adverb_id IN (SELECT adverb_id FROM adverb_pronunciations WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; conditions.push_back(cond); - for (auto rhyme : _rhymes) + for (auto rhy : _rhymes) { - bindings.emplace_back("%" + rhyme); + bindings.emplace_back(rhy.get_prerhyme()); + bindings.emplace_back(rhy.get_rhyme()); } } + if (_has_rhyming_noun) + { + 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)"); + } + + if (_has_rhyming_adjective) + { + 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)"); + } + + if (_has_rhyming_adverb) + { + 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)"); + } + + if (_has_rhyming_verb) + { + 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)"); + } + for (auto except : _except) { conditions.push_back("adverb_id != ?"); @@ -538,7 +587,7 @@ namespace verbly { case binding::type::string: { - sqlite3_bind_text(ppstmt, i, binding.get_string().c_str(), binding.get_string().length(), SQLITE_STATIC); + sqlite3_bind_text(ppstmt, i, binding.get_string().c_str(), binding.get_string().length(), SQLITE_TRANSIENT); break; } @@ -601,7 +650,7 @@ namespace verbly { for (auto& adverb : output) { - query = "SELECT pronunciation FROM adverb_pronunciations WHERE adverb_id = ?"; + query = "SELECT pronunciation, prerhyme, rhyme FROM adverb_pronunciations WHERE adverb_id = ?"; if (sqlite3_prepare_v2(_data.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK) { throw std::runtime_error(sqlite3_errmsg(_data.ppdb)); @@ -615,6 +664,13 @@ namespace verbly { auto phonemes = verbly::split>(pronunciation, " "); adverb.pronunciations.push_back(phonemes); + + if ((sqlite3_column_type(ppstmt, 1) != SQLITE_NULL) && (sqlite3_column_type(ppstmt, 2) != SQLITE_NULL)) + { + std::string prerhyme(reinterpret_cast(sqlite3_column_text(ppstmt, 1))); + std::string rhyming(reinterpret_cast(sqlite3_column_text(ppstmt, 2))); + adverb.rhymes.emplace_back(prerhyme, rhyming); + } } 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 { adverb_query& except(const adverb& _word); adverb_query& rhymes_with(const word& _word); adverb_query& has_pronunciation(); + adverb_query& has_rhyming_noun(); + adverb_query& has_rhyming_adjective(); + adverb_query& has_rhyming_adverb(); + adverb_query& has_rhyming_verb(); adverb_query& requires_comparative_form(); adverb_query& requires_superlative_form(); @@ -41,9 +45,13 @@ namespace verbly { const data& _data; int _limit = unlimited; bool _random = false; - std::list _rhymes; + std::list _rhymes; std::list _except; bool _has_prn = false; + bool _has_rhyming_noun = false; + bool _has_rhyming_adjective = false; + bool _has_rhyming_adverb = false; + bool _has_rhyming_verb = false; bool _requires_comparative_form = false; 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 @@ #include "verbly.h" namespace verbly { - + data::data(std::string datafile) { 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 { case binding::type::string: { - sqlite3_bind_text(ppstmt, i, binding.get_string().c_str(), binding.get_string().length(), SQLITE_STATIC); + sqlite3_bind_text(ppstmt, i, binding.get_string().c_str(), binding.get_string().length(), SQLITE_TRANSIENT); break; } 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 { noun_query& noun_query::rhymes_with(const word& _word) { - for (auto rhyme : _word.rhyme_phonemes()) + for (auto rhyme : _word.get_rhymes()) { _rhymes.push_back(rhyme); } @@ -53,6 +53,34 @@ namespace verbly { return *this; } + noun_query& noun_query::has_rhyming_noun() + { + _has_rhyming_noun = true; + + return *this; + } + + noun_query& noun_query::has_rhyming_adjective() + { + _has_rhyming_adjective = true; + + return *this; + } + + noun_query& noun_query::has_rhyming_adverb() + { + _has_rhyming_adverb = true; + + return *this; + } + + noun_query& noun_query::has_rhyming_verb() + { + _has_rhyming_verb = true; + + return *this; + } + noun_query& noun_query::with_singular_form(std::string _arg) { _with_singular_form.push_back(_arg); @@ -483,16 +511,37 @@ namespace verbly { if (!_rhymes.empty()) { - std::list clauses(_rhymes.size(), "pronunciation LIKE ?"); + std::list clauses(_rhymes.size(), "(prerhyme != ? AND rhyme = ?)"); std::string cond = "noun_id IN (SELECT noun_id FROM noun_pronunciations WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; conditions.push_back(cond); - for (auto rhyme : _rhymes) + for (auto rhy : _rhymes) { - bindings.emplace_back("%" + rhyme); + bindings.emplace_back(rhy.get_prerhyme()); + bindings.emplace_back(rhy.get_rhyme()); } } + if (_has_rhyming_noun) + { + 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)"); + } + + if (_has_rhyming_adjective) + { + 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)"); + } + + if (_has_rhyming_adverb) + { + 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)"); + } + + if (_has_rhyming_verb) + { + 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)"); + } + for (auto except : _except) { conditions.push_back("noun_id != ?"); @@ -1768,7 +1817,7 @@ namespace verbly { { throw std::runtime_error(sqlite3_errmsg(_data.ppdb)); } - + int i = 1; for (auto& binding : bindings) { @@ -1783,7 +1832,7 @@ namespace verbly { case binding::type::string: { - sqlite3_bind_text(ppstmt, i, binding.get_string().c_str(), binding.get_string().length(), SQLITE_STATIC); + sqlite3_bind_text(ppstmt, i, binding.get_string().c_str(), binding.get_string().length(), SQLITE_TRANSIENT); break; } @@ -1791,7 +1840,7 @@ namespace verbly { i++; } - + /* for (auto adj : _derived_from_adjective) { @@ -1843,7 +1892,7 @@ namespace verbly { for (auto& noun : output) { - query = "SELECT pronunciation FROM noun_pronunciations WHERE noun_id = ?"; + query = "SELECT pronunciation, prerhyme, rhyme FROM noun_pronunciations WHERE noun_id = ?"; if (sqlite3_prepare_v2(_data.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK) { throw std::runtime_error(sqlite3_errmsg(_data.ppdb)); @@ -1857,6 +1906,14 @@ namespace verbly { auto phonemes = verbly::split>(pronunciation, " "); noun.pronunciations.push_back(phonemes); + + if ((sqlite3_column_type(ppstmt, 1) != SQLITE_NULL) && (sqlite3_column_type(ppstmt, 2) != SQLITE_NULL)) + { + std::string prerhyme(reinterpret_cast(sqlite3_column_text(ppstmt, 1))); + std::string rhyming(reinterpret_cast(sqlite3_column_text(ppstmt, 2))); + + noun.rhymes.emplace_back(prerhyme, rhyming); + } } 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 { noun_query& except(const noun& _word); noun_query& rhymes_with(const word& _word); noun_query& has_pronunciation(); + noun_query& has_rhyming_noun(); + noun_query& has_rhyming_adjective(); + noun_query& has_rhyming_adverb(); + noun_query& has_rhyming_verb(); noun_query& with_singular_form(std::string _arg); noun_query& with_prefix(filter _f); @@ -86,9 +90,13 @@ namespace verbly { const data& _data; int _limit = unlimited; bool _random = false; - std::list _rhymes; + std::list _rhymes; std::list _except; bool _has_prn = false; + bool _has_rhyming_noun = false; + bool _has_rhyming_adjective = false; + bool _has_rhyming_adverb = false; + bool _has_rhyming_verb = false; std::list _with_singular_form; filter _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 { case binding::type::string: { - sqlite3_bind_text(ppstmt, i, binding.get_string().c_str(), binding.get_string().length(), SQLITE_STATIC); + sqlite3_bind_text(ppstmt, i, binding.get_string().c_str(), binding.get_string().length(), SQLITE_TRANSIENT); break; } 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 { verb_query& verb_query::rhymes_with(const word& _word) { - for (auto rhyme : _word.rhyme_phonemes()) + for (auto rhyme : _word.get_rhymes()) { _rhymes.push_back(rhyme); } @@ -53,6 +53,34 @@ namespace verbly { return *this; } + verb_query& verb_query::has_rhyming_noun() + { + _has_rhyming_noun = true; + + return *this; + } + + verb_query& verb_query::has_rhyming_adjective() + { + _has_rhyming_adjective = true; + + return *this; + } + + verb_query& verb_query::has_rhyming_adverb() + { + _has_rhyming_adverb = true; + + return *this; + } + + verb_query& verb_query::has_rhyming_verb() + { + _has_rhyming_verb = true; + + return *this; + } + verb_query& verb_query::has_frames() { this->_has_frames = true; @@ -74,16 +102,37 @@ namespace verbly { if (!_rhymes.empty()) { - std::list clauses(_rhymes.size(), "pronunciation LIKE ?"); + std::list clauses(_rhymes.size(), "(prerhyme != ? AND rhyme = ?)"); std::string cond = "verb_id IN (SELECT verb_id FROM verb_pronunciations WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; conditions.push_back(cond); - for (auto rhyme : _rhymes) + for (auto rhy : _rhymes) { - bindings.emplace_back("%" + rhyme); + bindings.emplace_back(rhy.get_prerhyme()); + bindings.emplace_back(rhy.get_rhyme()); } } + if (_has_rhyming_noun) + { + 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)"); + } + + if (_has_rhyming_adjective) + { + 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)"); + } + + if (_has_rhyming_adverb) + { + 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)"); + } + + if (_has_rhyming_verb) + { + 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)"); + } + for (auto except : _except) { conditions.push_back("verb_id != ?"); @@ -132,7 +181,7 @@ namespace verbly { case binding::type::string: { - sqlite3_bind_text(ppstmt, i, binding.get_string().c_str(), binding.get_string().length(), SQLITE_STATIC); + sqlite3_bind_text(ppstmt, i, binding.get_string().c_str(), binding.get_string().length(), SQLITE_TRANSIENT); break; } @@ -158,7 +207,7 @@ namespace verbly { for (auto& verb : output) { - query = "SELECT pronunciation FROM verb_pronunciations WHERE verb_id = ?"; + query = "SELECT pronunciation, prerhyme, rhyme FROM verb_pronunciations WHERE verb_id = ?"; if (sqlite3_prepare_v2(_data.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK) { throw std::runtime_error(sqlite3_errmsg(_data.ppdb)); @@ -172,6 +221,13 @@ namespace verbly { auto phonemes = verbly::split>(pronunciation, " "); verb.pronunciations.push_back(phonemes); + + if ((sqlite3_column_type(ppstmt, 1) != SQLITE_NULL) && (sqlite3_column_type(ppstmt, 2) != SQLITE_NULL)) + { + std::string prerhyme(reinterpret_cast(sqlite3_column_text(ppstmt, 1))); + std::string rhyming(reinterpret_cast(sqlite3_column_text(ppstmt, 2))); + verb.rhymes.emplace_back(prerhyme, rhyming); + } } 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 { verb_query& except(const verb& _word); verb_query& rhymes_with(const word& _word); verb_query& has_pronunciation(); + verb_query& has_rhyming_noun(); + verb_query& has_rhyming_adjective(); + verb_query& has_rhyming_adverb(); + verb_query& has_rhyming_verb(); verb_query& has_frames(); @@ -23,10 +27,14 @@ namespace verbly { const data& _data; int _limit = unlimited; bool _random = false; - std::list _rhymes; + std::list _rhymes; std::list _except; bool _has_prn = false; bool _has_frames = false; + bool _has_rhyming_noun = false; + bool _has_rhyming_adjective = false; + bool _has_rhyming_adverb = false; + bool _has_rhyming_verb = false; }; }; 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 @@ namespace verbly { + rhyme::rhyme(std::string prerhyme, std::string phonemes) : _prerhyme(prerhyme), _rhyme(phonemes) + { + + } + + std::string rhyme::get_prerhyme() const + { + return _prerhyme; + } + + std::string rhyme::get_rhyme() const + { + return _rhyme; + } + + bool rhyme::operator==(const rhyme& other) const + { + return std::tie(_prerhyme, _rhyme) == std::tie(other._prerhyme, other._rhyme); + } + word::word() { @@ -13,28 +33,11 @@ namespace verbly { } - std::list word::rhyme_phonemes() const + std::list word::get_rhymes() const { assert(_valid == true); - std::list result; - - for (auto pronunciation : pronunciations) - { - auto phemstrt = std::find_if(std::begin(pronunciation), std::end(pronunciation), [] (std::string phoneme) { - return phoneme.find("1") != std::string::npos; - }); - - std::stringstream rhymer; - for (auto it = phemstrt; it != std::end(pronunciation); it++) - { - rhymer << " " << *it; - } - - result.push_back(rhymer.str()); - } - - return result; + return rhymes; } 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 @@ namespace verbly { + class rhyme { + public: + rhyme(std::string prerhyme, std::string phonemes); + + std::string get_prerhyme() const; + std::string get_rhyme() const; + + bool operator==(const rhyme& other) const; + + private: + std::string _prerhyme; + std::string _rhyme; + }; + class word { protected: const data* _data; @@ -10,6 +24,7 @@ namespace verbly { bool _valid = false; std::list> pronunciations; + std::list rhymes; word(); word(const data& _data, int _id); @@ -24,7 +39,7 @@ namespace verbly { public: virtual std::string base_form() const = 0; - std::list rhyme_phonemes() const; + std::list get_rhymes() const; bool starts_with_vowel_sound() const; }; -- cgit 1.4.1