diff --git a/src/data/card.cpp b/src/data/card.cpp index be2ab4ce..4c0d157a 100644 --- a/src/data/card.cpp +++ b/src/data/card.cpp @@ -57,10 +57,24 @@ String Card::identification() const { bool Card::contains(String const& query) const { FOR_EACH_CONST(v, data) { - if (v->toString().find(query) != String::npos) return true; + if (find_i(v->toString(),query) != String::npos) return true; } return false; } +bool Card::contains_words(String const& query) const { + // iterate over the words + for (size_t i = 0 ; i < query.size() ; ) { + size_t end = query.find_first_of(_(" "),i); + if (end == i) { + i++; + } else { + end = min(end,query.size()); + if (!contains(query.substr(i,end-i))) return false; + i = end; + } + } + return true; +} IndexMap& Card::extraDataFor(const StyleSheet& stylesheet) { return extra_data.get(stylesheet.name(), stylesheet.extra_card_fields); diff --git a/src/data/card.hpp b/src/data/card.hpp index 644857d9..eaf68558 100644 --- a/src/data/card.hpp +++ b/src/data/card.hpp @@ -63,6 +63,8 @@ class Card : public IntrusivePtrVirtualBase { String identification() const; /// Does any field contains the given query string? bool contains(String const& query) const; + /// Does this card contain each of the words in the query string? + bool contains_words(String const& query) const; /// Find a value in the data by name and type template T& value(const String& name) { diff --git a/src/gui/control/filtered_card_list.cpp b/src/gui/control/filtered_card_list.cpp index 493931fd..8006c557 100644 --- a/src/gui/control/filtered_card_list.cpp +++ b/src/gui/control/filtered_card_list.cpp @@ -45,6 +45,6 @@ void CardListFilter::getItems(const vector& cards, vector& out) co } bool QueryCardListFilter::keep(const CardP& card) const { - return card->contains(query); + return card->contains_words(query); } diff --git a/src/util/string.cpp b/src/util/string.cpp index 398ceffc..a24d8c39 100644 --- a/src/util/string.cpp +++ b/src/util/string.cpp @@ -413,6 +413,14 @@ bool cannocial_name_compare(const String& as, const Char* b) { } } +size_t find_i(const String& heystack, const String& needle) { + if (needle.empty()) return 0; + for (size_t i = 0 ; i + needle.size() <= heystack.size() ; ++i) { + if (is_substr_i(heystack, i, needle)) return true; + } + return String::npos; +} + // ----------------------------------------------------------------------------- : Regular expressions /// Escape a single character for use in regular expressions diff --git a/src/util/string.hpp b/src/util/string.hpp index b4a544b9..65b79b38 100644 --- a/src/util/string.hpp +++ b/src/util/string.hpp @@ -199,6 +199,9 @@ bool is_substr_i(const String& str, size_t pos, const Char* cmp); /// Return whether str contains the string cmp at position pos, case insensitive compare bool is_substr_i(const String& str, size_t pos, const String& cmp); +/// Case insensitive string search, returns String::npos if not found +size_t find_i(const String& heystack, const String& needle); + /// Compare two strings for equality, b may contain '_' where a contains ' ' bool cannocial_name_compare(const String& a, const Char* b);