2009-12-23 69 views
3

我對STL很陌生,對C++來說很新。我試圖得到一個.NET的等價物,但是在C++中。這大致就是我想:如何使用hash_map和不區分大小寫的unicode字符串作爲鍵?

stdext::hash_map<LPCWSTR, SomeStruct> someMap; 
someMap.insert(stdext::pair<LPCWSTR, SomeStruct>(L"a string", struct)); 
someMap.find(L"a string") 
someMap.find(L"A STRING") 

麻煩的是,既沒有發現操作通常工作(它返回someMap.end())。它似乎有時可以工作,但大部分時間沒有。我猜測hash_map使用的散列函數正在散列字符串的內存地址,而不是字符串本身的內容,而且幾乎肯定不區分大小寫。

我該如何獲得一個使用不區分大小寫的鍵的字典式結構,並且可以存儲我的自定義結構?

謝謝。

+0

'hash_map'不是STL或任何當前或計劃的C++標準庫的一部分。也許你在談論'TR1 :: unordered_map'? – 2009-12-23 00:09:10

+0

我指的是Visual C++中包含的一個,如此處所述:http://msdn.microsoft.com/en-us/library/0d462wfh(VS.100).aspx – 2009-12-23 00:15:24

+0

STL是否有內置的解決方案這個問題? – 2009-12-23 00:15:57

回答

0

LPCWSTR是一個指向以空字符結尾的unicode字符數組的指針,在這種情況下可能不是您想要的。相反,請使用basic_string的專業wstring

對於不區分大小寫,您需要在插入和搜索之前將鍵轉換爲全部大寫或全部小寫。至少我不認爲你可以用其他方式做到這一點。

1

如果使用std::map而不是非標準hash_map,你可以設置比較函數做二進制搜索時使用:

// Function object for case insensitive comparison 
struct case_insensitive_compare 
{ 
    case_insensitive_compare() {} 

    // Function objects overloader operator() 
    // When used as a comparer, it should function as operator<(a,b) 
    bool operator()(const std::string& a, const std::string& b) const 
    { 
     return to_lower(a) < to_lower(b); 
    } 

    std::string to_lower(const std::string& a) const 
    { 
     std::string s(a); 
     std::for_each(s.begin(), s.end(), char_to_lower); 
     return s; 
    } 

    void char_to_lower(char& c) const 
    { 
     if (c >= 'A' && c <= 'Z') 
      c += ('a' - 'A'); 
    } 
}; 

// ... 

std::map<std::string, std::string, case_insensitive_compare> someMap; 
someMap["foo"] = "Hello, world!"; 
std::cout << someMap["FOO"] << endl; // Hello, world! 
+0

謝謝。儘管我自己的拉丁語只是小寫轉換,但我選擇在比較函數中使用_wcsicmp函數。 – 2009-12-23 04:03:43

3

您鏈接到的hash_map文件表明您可以提供你自己的特質類作爲第三個模板參數。這必須滿足與hash_compare相同的界面。

掃描的文檔,我認爲你必須做的這是什麼,這基本上取代你在你的字典有使用StringComparer.OrdinalIgnoreCase

struct my_hash_compare { 
    const size_t bucket_size = 4; 
    const size_t min_buckets = 8; 
    size_t operator()(const LPCWSTR &Key) const { 
     // implement a case-insensitive hash function here, 
     // or find something in the Windows libraries. 
    } 
    bool operator()(const LPCWSTR &Key1, const LPCWSTR &Key2) const { 
     // implement a case-insensitive comparison function here 
     return _wcsicmp(Key1, Key2) < 0; 
     // or something like that. There's warnings about 
     // locale plastered all over this function's docs. 
    } 
}; 

我很擔心,但該文檔說,比較函數必須是一個總的順序,而不是像C++標準庫中的排序容器通常那樣嚴格的弱順序。如果MS確實意味着全部訂單,那麼hash_map可能依賴於它與operator==一致。也就是說,他們可能會要求如果my_hash_compare()(a,b)爲假,並且my_hash_compare()(b,a)爲假,那麼a == b。很明顯,這不符合我寫的內容,在這種情況下,你運氣不好。

作爲一種替代方案,在任何情況下可能效率更高,您可以在地圖中使用它們之前將所有按鍵都推送到常見情況。不區分大小寫的比較比常規字符串比較成本更高。儘管如此,還是有一些Unicode技術可以解決這個問題。也許你必須轉換 - >小寫 - >大寫,而不是隻是 - >大寫,或類似的東西,以避免在某些語言或標題字符的一些討厭的情況。任何人?

正如其他人所說,你可能不希望LPCWSTR作爲你的鑰匙。這將在地圖中存儲指針,這意味着插入字符串的任何人都必須確保指向的數據保持有效,只要它位於hash_map中即可。從長遠來看,hash_map通常會將密鑰字符串的副本傳遞給insert,在這種情況下,您應該使用wstring作爲關鍵。

+0

bucket_size,min_buckets應該是靜態的 – 2011-06-21 10:13:30

+0

@Yochai:只有當你想要它編譯。我修正了它,但是現在我已經解決了它,因爲我從MSDN複製了那部分而沒有真正查看它。這不是我不知道的一些奇怪的MS擴展,是嗎? – 2011-06-21 10:19:31

2

這裏給出了一些很好的信息。我收集了答案中的部分代碼並將它們放在一起:

#include "stdafx.h" 
#include "atlbase.h" 
#include <map> 
#include <wchar.h> 

typedef std::pair<std::wstring, int> MyPair; 

struct key_comparer 
{ 
    bool operator()(std::wstring a, std::wstring b) const 
    { 
     return _wcsicmp(a.c_str(), b.c_str()) < 0; 
    } 
}; 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    std::map<std::wstring, int, key_comparer> mymap; 
    mymap.insert(MyPair(L"GHI",3)); 
    mymap.insert(MyPair(L"DEF",2)); 
    mymap.insert(MyPair(L"ABC",1)); 

    std::map<std::wstring, int, key_comparer>::iterator iter; 
    iter = mymap.find(L"def"); 
    if (iter == mymap.end()) { 
     printf("No match.\n"); 
    } else { 
     printf("match: %i\n", iter->second); 
    } 
    return 0; 
} 
相關問題