2009-11-26 78 views

回答

59

它不會默認。您必須提供一個自定義比較器作爲第三個參數。下面的代碼片段將幫助你......

/************************************************************************/ 
    /* 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;

注意:性病:: lexicographical_compare有一些細枝末節。如果考慮語言環境,字符串比較並不總是直截了當的。如果感興趣,請參閱c1.C++上的this線程。

UPDATE:使用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 
    } 
    }; 
+0

@Abhay。感謝您的回答。但是,我不完全確定這是如何工作的(對STL來說相對較新)。如何定義第三個參數,即比較函數或函數對象做「不區分大小寫」,實際上不區分大小寫的比較。我們不應該使用==運算符來代替。這實際上是如何工作的。我確定我正在做點什麼。 – Ankur 2009-11-26 07:56:43

+1

@Ankur:std :: map通常實現爲某種樹形結構。 find()方法使用用於排序的比較函數(一個既不在前面也不在後面的項目被認爲是相等的 - 也就是嚴格的弱排序)。這允許使用地圖的樹結構在O(logN)時間內執行搜索。謂詞對象非常像一個排序函數;它的operator()接受一個MyMap :: value_type&作爲參考, 並且如果該項目符合您的搜索標準,則返回true。 – Abhay 2009-11-26 08:06:24

+0

@Ankur:同樣,根據std :: map的簽名std :: map ,'Compare'是一個'Strict Weak Ordering',其參數類型爲Key。樹是使用這種順序構建的。若要查看數學術語中的嚴格無序排序,請閱讀簡化的SGI文章@ http://www.sgi.com/tech/stl/StrictWeakOrdering.html – Abhay 2009-11-26 08:20:51

2

不,你不能這樣做,使用find在這種情況下,將有多個比賽。例如,雖然插入可以讓您完成類似map["A"] = 1map["a"] = 2的操作,但現在如果您想區分大小寫map.find("a"),則預期返回值是多少?解決這個問題的最簡單方法是隻在一種情況下(大寫或小寫)將字符串插入到映射中,然後在執行查找時使用相同的大小寫。

+0

-1,誤導。不區分大小寫映射的期望值將簡單地爲2(最後一個值寫爲A「==」a「)。映射使用嚴格的弱排序,它們可以具有相同的鍵,任何這樣的鍵都可以互換使用。 – MSalters 2009-11-26 09:44:32

+0

可能會產生誤導。我試圖展示的是,如果您有區分大小寫的映射,則無法使用find()函數以不區分大小寫的方式工作。 – Naveen 2009-11-26 09:54:18

+0

公平點,但這一點會很多例如,如果你已經解釋過std :: map只支持一個索引,它可以區分大小寫而不區分大小寫,但不能同時存在,從這裏可以輕鬆鏈接到'boost :: multi_index',確實支持第二個索引 – MSalters 2009-11-26 13:41:51

6

您可以參數實例std::map:鑰匙的類型,值類型和比較功能 - 一個嚴格弱排序(實際上是一個函數或函數對象而言表現得像operator<的傳遞性和反反射性)你喜歡的。只需定義第三個參數來執行「不區分大小寫」(例如,通過它所比較的​​小寫字符串上的<),並且您將擁有所需的「不區分大小寫的地圖」!

0

執行std :: less函數並通過將兩者都更改爲相同大小進行比較。

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 ?,直接字符串比較器?)

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

+1對於酷,但哇,這是醜陋的。讓它成爲我的例子中的仿函數,然後輸入地圖。 – 2010-06-09 20:43:57

22

這裏有一些其他的替代品,包括其中一個顯著執行速度要快。

#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; 
} 
+2

'?第一種方法中的「1:0」部分是愚蠢且不必要的,但是否則就是很好的答案。 – jcoffland 2012-11-10 05:50:33

+0

僅供參考,strcasecmp()不在中。它在,但我不認爲Windows有它。 – jcoffland 2012-11-10 06:05:34

+1

當你說'是x <0'的時候,你現在已經有了一個布爾值,那麼爲什麼你會產生一個整數,然後必須轉換爲布爾值來匹配返回參數? – 2013-10-22 14:19:41

1

測試:

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 
0

對於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; 
}