49

map::findメソッドは大文字と小文字を区別しない検索をサポートしていますか? 次のようなマップがあります。

map<string, vector<string> > directory;

以下の検索で大文字と小文字を区別しないようにします。

directory.find(search_string);
4

11 に答える 11

69

デフォルトではありません。3 番目の引数としてカスタム コンパレータを指定する必要があります。次のスニペットが役立ちます...

  /************************************************************************/
  /* 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 には、いくつかの重要な詳細があります。ロケールを考慮すると、文字列の比較は必ずしも簡単ではありません。興味がある場合は、clc++ のこのスレッドを参照してください。

UPDATE : With C++11std::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
    }
  };
于 2009-11-26T06:39:01.610 に答える
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;
}
于 2010-06-09T20:45:44.297 に答える
6

私は以下を使用します:

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);
于 2010-01-06T09:05:14.540 に答える
6

キーの型、値の型、および比較関数3 つのstd::mapパラメーターを使用してインスタンス化できます。厳密な弱い順序付け(基本的に、推移性と反反射性の観点から動作する関数またはファンクター) です。3 番目のパラメーターを定義して、「大文字と小文字を区別しないより小なり」(たとえば、比較対象の小文字の文字列に対して a を使用) を行うだけで、必要な「大文字と小文字を区別しないマップ」が得られます。operator<<

于 2009-11-26T06:39:43.590 に答える
4

findいいえ、その場合は複数の一致があるため、それを使用することはできません。たとえば、挿入するmap["A"] = 1map["a"] = 2、次のようなことができますが、大文字と小文字を区別しない場合map.find("a")、期待される戻り値は何ですか? これを解決する最も簡単な方法は、文字列を 1 つのケース (大文字または小文字) だけでマップに挿入し、検索中に同じケースを使用することです。

于 2009-11-26T06:36:45.187 に答える
4

マップ タイプに触れたくない場合 (元のシンプルさと効率を維持するため)、大文字と小文字を区別しない遅い検索関数 (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: ロジャー ペイトのアイデアだったのかもしれませんが、一部の詳細が少しずれていたため、わかりません (std::search?、直接文字列コンパレータ?)。

于 2009-11-26T17:29:03.530 に答える
2

Boost やテンプレートを使用しない簡単な解決策を提示したいと思います。C++11以降、ラムダ式をカスタム コンパレータとしてマップに提供することもできます。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 のコード

ウィンドウのstrcasecmp()場合、存在しませんが、_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 をサポートする必要があるかどうかによって、別の方法で文字列を比較する必要がある場合があります。この Q&Aは良いスタートになります。

于 2019-03-15T14:12:15.553 に答える
1

マップ テンプレートの Compare 要素のデフォルトは、バイナリ比較クラス「less」です。実装を見てください:

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

binary_function (less の親クラス) から派生する独自のクラスを作成し、大文字と小文字を区別せずに同じ比較を行うことができます。

于 2009-11-26T06:37:09.617 に答える
0

std::less 関数を実装し、両方を同じケースに変更して比較します。

于 2009-11-26T06:49:39.903 に答える