使map :: find操作不敏感

Ank*_*kur 47 c++ string dictionary stl case-insensitive

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

map<string, vector<string> > directory;
Run Code Online (Sandbox Code Playgroud)

并希望下面的搜索忽略大小写.

directory.find(search_string);
Run Code Online (Sandbox Code Playgroud)

Abh*_*hay 66

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

  /************************************************************************/
  /* 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
    }
  };
Run Code Online (Sandbox Code Playgroud)

像它一样使用它 std::map< std::string, std::vector<std::string>, ci_less > myMap;

注意:std :: lexicographical_compare有一些细节.如果考虑区域设置,字符串比较并不总是直截了当.如果感兴趣,请参阅clc ++上的这个主题.

更新:std::binary_function不推荐使用C++ 11 ,因为类型是自动推断的.

  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
    }
  };
Run Code Online (Sandbox Code Playgroud)

  • @Ankur:std :: map通常实现为某种树结构。find()方法使用比较函数,该函数用于对树进行排序(将之前或之后出现的项目均视为相等,即严格的弱排序)。这允许使用地图的树结构在O(logN)时间内执行搜索。谓词对象非常类似于排序函数。其operator()以MyMap :: value_type&作为参考,如果该项与您的搜索条件匹配,则返回true。 (2认同)

Rob*_*nes 23

以下是一些其他替代方案,包括性能明显更快的方案.

#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;
}
Run Code Online (Sandbox Code Playgroud)

  • '?第一种方法中的1:0'部分是愚蠢的,没有必要,但另外很好的答案. (2认同)

Jam*_*mes 7

对于 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;
}
Run Code Online (Sandbox Code Playgroud)


Ale*_*lli 6

您可以std::map使用三个参数进行实例化:键的类型,值的类型和比较函数 - 您喜欢的严格弱排序(本质上,函数或函数,就像operator<传递性和反反射性而言).只需定义第三个参数来做"不区分大小写的情况"(例如通过<它比较的小写字符串),你就会得到你想要的"不区分大小写的地图"!


小智 5

如果您不想触及地图类型(以保持其原始的简单性和效率),但不介意使用较慢的不区分大小写的查找函数(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));
}
Run Code Online (Sandbox Code Playgroud)

PS:也许这是罗杰·佩特的想法,但不确定,因为一些细节有点偏离(std::search?,直接字符串比较器?)


Man*_*uel 5

我使用以下内容:

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);
Run Code Online (Sandbox Code Playgroud)

  • +1为了凉爽,但哇,这很难看.使它像我的例子中的仿函数和typedef地图. (2认同)