使map :: find操作不区分大小写

map :: find方法是否支持不区分大小写的search?
我有一张地图如下

map<string,vector<string> > directory; 

并希望下面的search忽略大小写。

 directory.find(search_string); 

它不是默认的。 您将不得不提供一个自定义的比较器作为第三个参数。 以下代码将帮助你…

  /************************************************************************/ /* Comparator for case-insensitive comparison in STL assos. containers */ /************************************************************************/ struct ci_less : std::binary_function<std::string, std::string, bool> { // case-independent (ci) compare_less binary function struct nocase_compare : public std::binary_function<unsigned char,unsigned char,bool> { bool operator() (const unsigned char& c1, const unsigned char& c2) const { return tolower (c1) < tolower (c2); } }; bool operator() (const std::string & s1, const std::string & s2) const { return std::lexicographical_compare (s1.begin (), s1.end (), // source range s2.begin (), s2.end (), // dest range nocase_compare ()); // comparison } }; 

std::map< std::string, std::vector<std::string>, ci_less > myMap;

注意 :std :: lexicographical_compare有一些细节的细节。 如果考虑语言环境,string比较并不总是直截了当的。 如果感兴趣,请参阅clc ++上的这个线程。

更新 :使用C ++ 11 std::binary_function被弃用,并且是不必要的,因为types是自动推导的。

  struct ci_less { // case-independent (ci) compare_less binary function struct nocase_compare { bool operator() (const unsigned char& c1, const unsigned char& c2) const { return tolower (c1) < tolower (c2); } }; bool operator() (const std::string & s1, const std::string & s2) const { return std::lexicographical_compare (s1.begin (), s1.end (), // source range s2.begin (), s2.end (), // dest range nocase_compare ()); // comparison } }; 

这里有一些其他的select,其中包括更快的执行。

 #include <map> #include <string> #include <cstring> #include <iostream> #include <boost/algorithm/string.hpp> using std::string; using std::map; using std::cout; using std::endl; using namespace boost::algorithm; // recommended in Meyers, Effective STL when internationalization and embedded // NULLs aren't an issue. Much faster than the STL or Boost lex versions. struct ciLessLibC : public std::binary_function<string, string, bool> { bool operator()(const string &lhs, const string &rhs) const { return strcasecmp(lhs.c_str(), rhs.c_str()) < 0 ; } }; // Modification of Manuel's answer struct ciLessBoost : std::binary_function<std::string, std::string, bool> { bool operator() (const std::string & s1, const std::string & s2) const { return lexicographical_compare(s1, s2, is_iless()); } }; typedef map< string, int, ciLessLibC> mapLibc_t; typedef map< string, int, ciLessBoost> mapBoost_t; int main(void) { mapBoost_t cisMap; // change to test other comparitor cisMap["foo"] = 1; cisMap["FOO"] = 2; cisMap["bar"] = 3; cisMap["BAR"] = 4; cisMap["baz"] = 5; cisMap["BAZ"] = 6; cout << "foo == " << cisMap["foo"] << endl; cout << "bar == " << cisMap["bar"] << endl; cout << "baz == " << cisMap["baz"] << endl; return 0; } 

你可以使用三个参数来实例化std::map :键的types,值的types和比较函数 – 一个严格的弱sorting (本质上,一个函数或函子的行为像operator<在传递性和反自反性方面))喜好。 只要定义第三个参数来做“不区分大小写的小于”(例如,通过比较它的小写string上的< ),你就会得到你所希望的“不区分大小写的地图”!

我使用以下内容:

 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); 

如果您不想触摸地图types(保持原始的简单性和效率),但不介意使用较慢的不区分大小写的查找函数(O(N)):

 string to_lower(string s) { transform(s.begin(), s.end(), s.begin(), (int(*)(int)) tolower ); return s; } typedef map<string, int> map_type; struct key_lcase_equal { string lcs; key_lcase_equal(const string& s) : lcs(to_lower(s)) {} bool operator()(const map_type::value_type& p) const { return to_lower(p.first) == lcs; } }; map_type::iterator find_ignore_case(map_type& m, const string& s) { return find_if(m.begin(), m.end(), key_lcase_equal(s)); } 

PS:也许这是罗杰·皮特的想法,但不能确定,因为一些细节有点closures(std :: search ?,直接string比较器?)

不,你不能这样做,因为在这种情况下,会有多个匹配。 例如,当插入让你做了像map["A"] = 1map["a"] = 2 ,现在如果你想不区分大小写map.find("a")什么是预期的返回值? 解决这个问题的最简单的方法是只在一种情况下(大写或小写)将string插入到映射中,然后在执行查找时使用相同的大小写。

地图模板的Compare元素默认为二进制比较类“less”。 看看执行情况:

http://www.cplusplus.com/reference/std/functional/less/

你可能会创build自己的类,从binary_function派生(父类更less),并进行相同的比较,而不区分大小写。

testing:

 template<typename T> struct ci_less:std::binary_function<T,T,bool> { bool operator() (const T& s1,const T& s2) const { return boost::ilexicographical_compare(s1,s2); }}; ... map<string,int,ci_less<string>> x=boost::assign::map_list_of ("One",1) ("Two",2) ("Three",3); cout << x["one"] << x["TWO"] <<x["thrEE"] << endl; //Output: 123 

实现std :: less函数,并通过将两者更改为相同的大小进行比较。

对于C ++ 11及更高版本:

 #include <strings.h> #include <map> #include <string> namespace detail { struct CaseInsensitiveComparator { bool operator()(const std::string& a, const std::string& b) const noexcept { return ::strcasecmp(a.c_str(), b.c_str()) < 0; } }; } // namespace detail template <typename T> using CaseInsensitiveMap = std::map<std::string, T, detail::CaseInsensitiveComparator>; int main(int argc, char* argv[]) { CaseInsensitiveMap<int> m; m["one"] = 1; std::cout << m.at("ONE") << "\n"; return 0; }