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

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

map<string, vector<string> > directory;

并希望以下搜索忽略大小写:

directory.find(search_string);
Ankur asked 2020-06-27T16:44:35Z
11个解决方案
66 votes

默认情况下不是。 您将必须提供一个自定义比较器作为第三个参数。 以下片段将帮助您...

  /************************************************************************/
  /* 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::binary_function一样使用

注意:std :: lexicographical_compare具有一些细节。 如果考虑语言环境,字符串比较并不总是那么简单。 如果感兴趣,请参见c.l.c ++上的该线程。

更新:不推荐使用C ++ 11 std::binary_function,因为类型是自动推导的,因此不必要。

  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
    }
  };
Abhay answered 2020-06-27T16:44:57Z
23 votes

这是其他一些选择,包括执行速度明显更快的选择。

#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;
}
Robert S. Barnes answered 2020-06-27T16:45:17Z
6 votes

您可以使用三个参数实例化2941694114255055078400:键的类型,值的类型和比较函数-自己喜欢的严格弱排序(本质上,函数或函子的行为类似于operator<,在传递性和反反射性方面)。 只需定义第三个参数即可实现“不区分大小写的小于”(例如,通过它正在比较的小写字符串上的<),您将拥有所需的“不区分大小写的映射”!

Alex Martelli answered 2020-06-27T16:45:38Z
5 votes

我使用以下内容:

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);
Manuel answered 2020-06-27T16:45:58Z
4 votes

万一您不想触摸地图类型(以保持其原始的简单性和效率),但又不介意使用较慢的不区分大小写的查找功能(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:也许这是Roger Pate的想法,但不确定,因为有些细节有些偏离(std :: search ?,直接字符串比较器?)

Alink answered 2020-06-27T16:46:22Z
3 votes

不,您不能使用find进行操作,因为在这种情况下将有多个匹配项。 例如,在插入时,您可以执行map["A"] = 1map["a"] = 2之类的操作,现在,如果您希望使用不区分大小写的map.find("a"),期望的返回值是多少? 解决此问题的最简单方法是仅在一种情况下(大写或小写)将字符串插入map中,然后在查找时使用相同的大小写。

Naveen answered 2020-06-27T16:46:43Z
1 votes

映射模板的Compare元素默认为二进制比较类“ less”。 看一下实现:

[HTTP://呜呜呜.昌平路塞浦路斯.com/reference/实体店/functional/less/]

您可以创建自己的从binary_function派生的类(父类更少),并进行相同的比较而不区分大小写。

answered 2020-06-27T16:47:12Z
1 votes

经测试:

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
sz9 answered 2020-06-27T16:47:32Z
1 votes

对于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;
}
James answered 2020-06-27T16:47:51Z
0 votes

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

Vivek answered 2020-06-27T16:48:11Z
0 votes

我想提出一个简短的解决方案,而不使用Boost或模板。 从C ++ 11开始,您还可以提供lambda表达式作为映射的自定义比较器。 对于兼容POSIX的系统,解决方案如下所示:

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

Ideone上的代码

对于Window,不存在_stricmp(),但是可以改用_stricmp()

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

注意:根据您的系统以及是否必须支持Unicode,您可能需要以其他方式比较字符串。 此次问答为您提供了一个良好的开端。

honk answered 2020-06-27T16:48:45Z
translate from https://stackoverflow.com:/questions/1801892/how-can-i-make-the-mapfind-operation-case-insensitive