diff options
Diffstat (limited to 'xbmc/utils/TextSearch.cpp')
| -rw-r--r-- | xbmc/utils/TextSearch.cpp | 146 |
1 files changed, 146 insertions, 0 deletions
diff --git a/xbmc/utils/TextSearch.cpp b/xbmc/utils/TextSearch.cpp new file mode 100644 index 0000000..1ada61d --- /dev/null +++ b/xbmc/utils/TextSearch.cpp | |||
| @@ -0,0 +1,146 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2005-2018 Team Kodi | ||
| 3 | * This file is part of Kodi - https://kodi.tv | ||
| 4 | * | ||
| 5 | * SPDX-License-Identifier: GPL-2.0-or-later | ||
| 6 | * See LICENSES/README.md for more information. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include "TextSearch.h" | ||
| 10 | |||
| 11 | #include "StringUtils.h" | ||
| 12 | |||
| 13 | CTextSearch::CTextSearch(const std::string &strSearchTerms, bool bCaseSensitive /* = false */, TextSearchDefault defaultSearchMode /* = SEARCH_DEFAULT_OR */) | ||
| 14 | { | ||
| 15 | m_bCaseSensitive = bCaseSensitive; | ||
| 16 | ExtractSearchTerms(strSearchTerms, defaultSearchMode); | ||
| 17 | } | ||
| 18 | |||
| 19 | bool CTextSearch::IsValid(void) const | ||
| 20 | { | ||
| 21 | return m_AND.size() > 0 || m_OR.size() > 0 || m_NOT.size() > 0; | ||
| 22 | } | ||
| 23 | |||
| 24 | bool CTextSearch::Search(const std::string &strHaystack) const | ||
| 25 | { | ||
| 26 | if (strHaystack.empty() || !IsValid()) | ||
| 27 | return false; | ||
| 28 | |||
| 29 | std::string strSearch(strHaystack); | ||
| 30 | if (!m_bCaseSensitive) | ||
| 31 | StringUtils::ToLower(strSearch); | ||
| 32 | |||
| 33 | /* check whether any of the NOT terms matches and return false if there's a match */ | ||
| 34 | for (unsigned int iNotPtr = 0; iNotPtr < m_NOT.size(); iNotPtr++) | ||
| 35 | { | ||
| 36 | if (strSearch.find(m_NOT.at(iNotPtr)) != std::string::npos) | ||
| 37 | return false; | ||
| 38 | } | ||
| 39 | |||
| 40 | /* check whether at least one of the OR terms matches and return false if there's no match found */ | ||
| 41 | bool bFound(m_OR.empty()); | ||
| 42 | for (unsigned int iOrPtr = 0; iOrPtr < m_OR.size(); iOrPtr++) | ||
| 43 | { | ||
| 44 | if (strSearch.find(m_OR.at(iOrPtr)) != std::string::npos) | ||
| 45 | { | ||
| 46 | bFound = true; | ||
| 47 | break; | ||
| 48 | } | ||
| 49 | } | ||
| 50 | if (!bFound) | ||
| 51 | return false; | ||
| 52 | |||
| 53 | /* check whether all of the AND terms match and return false if one of them wasn't found */ | ||
| 54 | for (unsigned int iAndPtr = 0; iAndPtr < m_AND.size(); iAndPtr++) | ||
| 55 | { | ||
| 56 | if (strSearch.find(m_AND[iAndPtr]) == std::string::npos) | ||
| 57 | return false; | ||
| 58 | } | ||
| 59 | |||
| 60 | /* all ok, return true */ | ||
| 61 | return true; | ||
| 62 | } | ||
| 63 | |||
| 64 | void CTextSearch::GetAndCutNextTerm(std::string &strSearchTerm, std::string &strNextTerm) | ||
| 65 | { | ||
| 66 | std::string strFindNext(" "); | ||
| 67 | |||
| 68 | if (StringUtils::EndsWith(strSearchTerm, "\"")) | ||
| 69 | { | ||
| 70 | strSearchTerm.erase(0, 1); | ||
| 71 | strFindNext = "\""; | ||
| 72 | } | ||
| 73 | |||
| 74 | size_t iNextPos = strSearchTerm.find(strFindNext); | ||
| 75 | if (iNextPos != std::string::npos) | ||
| 76 | { | ||
| 77 | strNextTerm = strSearchTerm.substr(0, iNextPos); | ||
| 78 | strSearchTerm.erase(0, iNextPos + 1); | ||
| 79 | } | ||
| 80 | else | ||
| 81 | { | ||
| 82 | strNextTerm = strSearchTerm; | ||
| 83 | strSearchTerm.clear(); | ||
| 84 | } | ||
| 85 | } | ||
| 86 | |||
| 87 | void CTextSearch::ExtractSearchTerms(const std::string &strSearchTerm, TextSearchDefault defaultSearchMode) | ||
| 88 | { | ||
| 89 | std::string strParsedSearchTerm(strSearchTerm); | ||
| 90 | StringUtils::Trim(strParsedSearchTerm); | ||
| 91 | |||
| 92 | if (!m_bCaseSensitive) | ||
| 93 | StringUtils::ToLower(strParsedSearchTerm); | ||
| 94 | |||
| 95 | bool bNextAND(defaultSearchMode == SEARCH_DEFAULT_AND); | ||
| 96 | bool bNextOR(defaultSearchMode == SEARCH_DEFAULT_OR); | ||
| 97 | bool bNextNOT(defaultSearchMode == SEARCH_DEFAULT_NOT); | ||
| 98 | |||
| 99 | while (strParsedSearchTerm.length() > 0) | ||
| 100 | { | ||
| 101 | StringUtils::TrimLeft(strParsedSearchTerm); | ||
| 102 | |||
| 103 | if (StringUtils::StartsWith(strParsedSearchTerm, "!") || StringUtils::StartsWithNoCase(strParsedSearchTerm, "not")) | ||
| 104 | { | ||
| 105 | std::string strDummy; | ||
| 106 | GetAndCutNextTerm(strParsedSearchTerm, strDummy); | ||
| 107 | bNextNOT = true; | ||
| 108 | } | ||
| 109 | else if (StringUtils::StartsWith(strParsedSearchTerm, "+") || StringUtils::StartsWithNoCase(strParsedSearchTerm, "and")) | ||
| 110 | { | ||
| 111 | std::string strDummy; | ||
| 112 | GetAndCutNextTerm(strParsedSearchTerm, strDummy); | ||
| 113 | bNextAND = true; | ||
| 114 | } | ||
| 115 | else if (StringUtils::StartsWith(strParsedSearchTerm, "|") || StringUtils::StartsWithNoCase(strParsedSearchTerm, "or")) | ||
| 116 | { | ||
| 117 | std::string strDummy; | ||
| 118 | GetAndCutNextTerm(strParsedSearchTerm, strDummy); | ||
| 119 | bNextOR = true; | ||
| 120 | } | ||
| 121 | else | ||
| 122 | { | ||
| 123 | std::string strTerm; | ||
| 124 | GetAndCutNextTerm(strParsedSearchTerm, strTerm); | ||
| 125 | if (strTerm.length() > 0) | ||
| 126 | { | ||
| 127 | if (bNextAND) | ||
| 128 | m_AND.push_back(strTerm); | ||
| 129 | else if (bNextOR) | ||
| 130 | m_OR.push_back(strTerm); | ||
| 131 | else if (bNextNOT) | ||
| 132 | m_NOT.push_back(strTerm); | ||
| 133 | } | ||
| 134 | else | ||
| 135 | { | ||
| 136 | break; | ||
| 137 | } | ||
| 138 | |||
| 139 | bNextAND = (defaultSearchMode == SEARCH_DEFAULT_AND); | ||
| 140 | bNextOR = (defaultSearchMode == SEARCH_DEFAULT_OR); | ||
| 141 | bNextNOT = (defaultSearchMode == SEARCH_DEFAULT_NOT); | ||
| 142 | } | ||
| 143 | |||
| 144 | StringUtils::TrimLeft(strParsedSearchTerm); | ||
| 145 | } | ||
| 146 | } | ||
