Does the map::find method support case insensitive search? I have a map as follows:
map<string, vector<string> > directory;
and want the below search to ignore case:
directory.find(search_string);
Does the map::find method support case insensitive search? I have a map as follows:
map<string, vector<string> > directory;
and want the below search to ignore case:
directory.find(search_string);
I use the following:
bool str_iless(std::string const & a,
std::string const & b)
{
return boost::algorithm::lexicographical_compare(a, b,
boost::is_iless());
}
std::map<std::string, std::string,
boost::function<bool(std::string const &,
std::string const &)>
> case_insensitive_map(&str_iless);
I'd like to present a short solution without using Boost or templates. Since C++11 you can also provide a lambda expression as custom comparator to your map. For a POSIX-compatible system, the solution could look as follows:
auto comp = [](const std::string& s1, const std::string& s2) {
return strcasecmp(s1.c_str(), s2.c_str()) < 0;
};
std::map<std::string, std::vector<std::string>, decltype(comp)> directory(comp);
For Window, strcasecmp() does not exist, but you can use _stricmp() instead:
auto comp = [](const std::string& s1, const std::string& s2) {
return _stricmp(s1.c_str(), s2.c_str()) < 0;
};
std::map<std::string, std::vector<std::string>, decltype(comp)> directory(comp);
Note: Depending on your system and whether you have to support Unicode or not, you might need to compare strings in a different way. This Q&A gives a good start.
This is the cross-platform standard c++ solution unlike strcasecmp (which is only available for posix), without using any external libraries like boost, that I have personally written. It takes advantage of the comparison function of std::map.
#include <algorithm>
#include <cctype>
#include <iostream>
#include <map>
#include <string>
bool caseInsensitiveCompare(const std::string& a, const std::string& b) {
std::string aLower = a;
std::string bLower = b;
std::transform(aLower.begin(), aLower.end(), aLower.begin(), [](unsigned char c){ return std::tolower(c); });
std::transform(bLower.begin(), bLower.end(), bLower.begin(), [](unsigned char c){ return std::tolower(c); });
return aLower < bLower;
};
int main()
{
std::map<std::string, std::string, decltype(&caseInsensitiveCompare)> myMap(&caseInsensitiveCompare);
myMap.insert({"foo", "foo"});
myMap.insert({"bar", "bar"});
myMap.insert({"baz", "baz"});
auto it = myMap.find("FoO");
if (it != myMap.end()) std::cout << "Found FoO: " << it->second << std::endl;
else std::cout << "Not found FoO" << std::endl;
it = myMap.find("foo");
if (it != myMap.end()) std::cout << "Found foo: " << it->second << std::endl;
else std::cout << "Not found foo" << std::endl;
it = myMap.find("not contained");
if (it != myMap.end()) std::cout << "Found not contained: " << it->second << std::endl;
else std::cout << "Not found notcontained" << std::endl;
return 0;
}