commit c9730b4afaa95d6fdf7258a697e5608fac5d3456
parent eada515538eb5f0a63f31c15c04b6dfa56934f46
Author: cfillion <cfillion@users.noreply.github.com>
Date: Thu, 6 Jan 2022 01:44:28 -0500
filter: match synonymous words [p=2512900]
Diffstat:
3 files changed, 87 insertions(+), 2 deletions(-)
diff --git a/src/filter.cpp b/src/filter.cpp
@@ -17,7 +17,7 @@
#include "filter.hpp"
-#include <boost/algorithm/string/case_conv.hpp>
+#include <boost/algorithm/string.hpp>
Filter::Filter(const std::string &input)
: m_root(Group::MatchAll)
@@ -102,7 +102,7 @@ Filter::Group *Filter::Group::push(const std::string &buf, int *flags)
if(!(*flags & LiteralFlag)) {
if(buf == "NOT") {
- *flags ^= Token::NotFlag;
+ *flags ^= NotFlag;
return this;
}
else if(buf == "OR") {
@@ -133,6 +133,8 @@ Filter::Group *Filter::Group::push(const std::string &buf, int *flags)
return this;
}
+ else if(pushSynonyms(buf, flags))
+ return this;
}
m_nodes.push_back(std::make_unique<Token>(buf, *flags));
@@ -153,6 +155,46 @@ Filter::Group *Filter::Group::addSubGroup(const Type type, const int flags)
return ptr;
}
+bool Filter::Group::pushSynonyms(const std::string &buf, int *flags)
+{
+ static const std::vector<std::string> synonyms[] {
+ { "open", "display", "view", "show", "hide" },
+ { "delete", "clear", "remove", "erase" },
+ { "insert", "add" },
+ { "deselect", "unselect" },
+ };
+
+ auto *match = [&]() -> decltype(&*synonyms) {
+ for(const auto &synonym : synonyms) {
+ for(const auto &word : synonym) {
+ if(boost::iequals(buf, word))
+ return &synonym;
+ }
+ }
+ return nullptr;
+ }();
+
+ if(!match)
+ return false;
+
+ Group *notGroup;
+ if(*flags & NotFlag) {
+ notGroup = addSubGroup(MatchAll, NotFlag);
+ *flags ^= NotFlag;
+ }
+ else
+ notGroup = this;
+
+ Group *orGroup = notGroup->addSubGroup(MatchAny, 0);
+ if(!(*flags & FullWordFlag))
+ orGroup->m_nodes.push_back(std::make_unique<Token>(buf, *flags));
+ for(const auto &word : *match)
+ orGroup->m_nodes.push_back(std::make_unique<Token>(word, *flags | FullWordFlag));
+
+ *flags = 0;
+ return true;
+}
+
bool Filter::Group::match(const std::vector<std::string> &rows) const
{
for(const auto &node : m_nodes) {
diff --git a/src/filter.hpp b/src/filter.hpp
@@ -71,6 +71,7 @@ private:
private:
Group *addSubGroup(Type, int flags);
+ bool pushSynonyms(const std::string &, int *flags);
Group *m_parent;
Type m_type;
diff --git a/test/filter.cpp b/test/filter.cpp
@@ -363,3 +363,45 @@ TEST_CASE("AND grouping", M) {
REQUIRE(f.match({"d"}));
}
}
+
+TEST_CASE("synonymous words", M) {
+ Filter f;
+
+ SECTION("basic") {
+ f.set("open");
+ REQUIRE(f.match({"open"}));
+ REQUIRE(f.match({"display"}));
+ REQUIRE_FALSE(f.match({"door"}));
+ }
+
+ SECTION("case-insensitive") {
+ f.set("OPEN");
+ REQUIRE(f.match({"display"}));
+ }
+
+ SECTION("full-word synonyms") {
+ f.set("unselect");
+ REQUIRE(f.match({"unselect"}));
+ REQUIRE(f.match({"unselected"}));
+ REQUIRE(f.match({"deselect"}));
+ REQUIRE_FALSE(f.match({"deselected"}));
+ }
+
+ SECTION("preserve anchor flags") {
+ f.set("^insert");
+ REQUIRE(f.match({"add"}));
+ REQUIRE_FALSE(f.match({"don't add"}));
+ REQUIRE_FALSE(f.match({"not inserting things"}));
+ }
+
+ SECTION("NOT applies to all synonyms") {
+ f.set("NOT open");
+ REQUIRE(f.match({"foo bar"}));
+ REQUIRE_FALSE(f.match({"open display"}));
+ }
+
+ SECTION("clear flags for the next token") {
+ f.set("^open bar");
+ REQUIRE(f.match({"open bar"}));
+ }
+}