How to use hash_map with case-insensitive unicode for a key?

I am very new to STL and quite new to C ++ in general. I am trying to get the equivalent of .NET Dictionary<string, value>(StringComparer.OrdinalIgnoreCase), but in C ++. This is roughly what I'm trying:

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

The problem is that the search operation does not work (it returns someMap.end()). This seems to work sometimes, but in most cases it is not. I assume that the hash function used by hash_map is to hash the memory address of the string, not the contents of the string itself, and it is almost certainly not case sensitive.

How can I get a dictionary-like structure that uses case-insensitive keys and can store my own structure?

Thank.

+3
source share
4 answers

The hash_map documentation that you are referencing indicates that you can provide your own feature class as the third parameter to the template. This should match the same interface as hash_compare .

Scanning documents, I think you need to do this, which basically replaces the use StringComparer.OrdinalIgnoreCaseyou had in your dictionary:

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 warnings about
        // locale plastered all over this function docs.
    }
};

, , , , ++. MS , hash_map , operator==. , , if my_hash_compare()(a,b) , my_hash_compare()(b,a) - false, a == b. , , , .

, , , , , . , . Unicode , . , → → , → - , . -?

, , , , , LPCWSTR . , , , , , , , , hash_map. , hash_map , insert, wstring .

+3

. :

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

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!
+1

LPCWSTR is a pointer to a unicode character array with a null character, and probably not the one you want in this case. Use wstringspecialization instead basic_string.

For case insensitivity, you will need to convert the keys to all upper case or all lower case before inserting and searching. At least I don’t think you can do it otherwise.

0
source

Source: https://habr.com/ru/post/1726401/


All Articles