Merge pull request #26166 from ksooo/improve-plugin-ctx-menus
[xbmc.git] / xbmc / utils / TextSearch.cpp
blob1ada61dee33fc0abdb52ebb196f5fc54ba75a3ed
1 /*
2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
7 */
9 #include "TextSearch.h"
11 #include "StringUtils.h"
13 CTextSearch::CTextSearch(const std::string &strSearchTerms, bool bCaseSensitive /* = false */, TextSearchDefault defaultSearchMode /* = SEARCH_DEFAULT_OR */)
15 m_bCaseSensitive = bCaseSensitive;
16 ExtractSearchTerms(strSearchTerms, defaultSearchMode);
19 bool CTextSearch::IsValid(void) const
21 return m_AND.size() > 0 || m_OR.size() > 0 || m_NOT.size() > 0;
24 bool CTextSearch::Search(const std::string &strHaystack) const
26 if (strHaystack.empty() || !IsValid())
27 return false;
29 std::string strSearch(strHaystack);
30 if (!m_bCaseSensitive)
31 StringUtils::ToLower(strSearch);
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++)
36 if (strSearch.find(m_NOT.at(iNotPtr)) != std::string::npos)
37 return false;
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++)
44 if (strSearch.find(m_OR.at(iOrPtr)) != std::string::npos)
46 bFound = true;
47 break;
50 if (!bFound)
51 return false;
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++)
56 if (strSearch.find(m_AND[iAndPtr]) == std::string::npos)
57 return false;
60 /* all ok, return true */
61 return true;
64 void CTextSearch::GetAndCutNextTerm(std::string &strSearchTerm, std::string &strNextTerm)
66 std::string strFindNext(" ");
68 if (StringUtils::EndsWith(strSearchTerm, "\""))
70 strSearchTerm.erase(0, 1);
71 strFindNext = "\"";
74 size_t iNextPos = strSearchTerm.find(strFindNext);
75 if (iNextPos != std::string::npos)
77 strNextTerm = strSearchTerm.substr(0, iNextPos);
78 strSearchTerm.erase(0, iNextPos + 1);
80 else
82 strNextTerm = strSearchTerm;
83 strSearchTerm.clear();
87 void CTextSearch::ExtractSearchTerms(const std::string &strSearchTerm, TextSearchDefault defaultSearchMode)
89 std::string strParsedSearchTerm(strSearchTerm);
90 StringUtils::Trim(strParsedSearchTerm);
92 if (!m_bCaseSensitive)
93 StringUtils::ToLower(strParsedSearchTerm);
95 bool bNextAND(defaultSearchMode == SEARCH_DEFAULT_AND);
96 bool bNextOR(defaultSearchMode == SEARCH_DEFAULT_OR);
97 bool bNextNOT(defaultSearchMode == SEARCH_DEFAULT_NOT);
99 while (strParsedSearchTerm.length() > 0)
101 StringUtils::TrimLeft(strParsedSearchTerm);
103 if (StringUtils::StartsWith(strParsedSearchTerm, "!") || StringUtils::StartsWithNoCase(strParsedSearchTerm, "not"))
105 std::string strDummy;
106 GetAndCutNextTerm(strParsedSearchTerm, strDummy);
107 bNextNOT = true;
109 else if (StringUtils::StartsWith(strParsedSearchTerm, "+") || StringUtils::StartsWithNoCase(strParsedSearchTerm, "and"))
111 std::string strDummy;
112 GetAndCutNextTerm(strParsedSearchTerm, strDummy);
113 bNextAND = true;
115 else if (StringUtils::StartsWith(strParsedSearchTerm, "|") || StringUtils::StartsWithNoCase(strParsedSearchTerm, "or"))
117 std::string strDummy;
118 GetAndCutNextTerm(strParsedSearchTerm, strDummy);
119 bNextOR = true;
121 else
123 std::string strTerm;
124 GetAndCutNextTerm(strParsedSearchTerm, strTerm);
125 if (strTerm.length() > 0)
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);
134 else
136 break;
139 bNextAND = (defaultSearchMode == SEARCH_DEFAULT_AND);
140 bNextOR = (defaultSearchMode == SEARCH_DEFAULT_OR);
141 bNextNOT = (defaultSearchMode == SEARCH_DEFAULT_NOT);
144 StringUtils::TrimLeft(strParsedSearchTerm);