GONJY_MONJY
@GONJY_MONJY
В поисках новых горизонтов

Как использовать русские символы из файла в качестве ключа для unordered_map?

Доброго времени суток!
Стоит такая задача: посчитать для каждого символа количество его вхождений в файле. Для этого я использую wifstream, дабы получить сам символ, а потом добавляю его в unordered_map, если такого ещё не было. Ну либо инкрементирую количество на единицу.

С английским текстом всё работает отлично, но только не с другими (например, русским и монгольским).

Сам код:

#include <iostream>
#include <fstream>
#include <unordered_map>
#include <Windows.h>

int main(int argc, char* argv[])
{
    SetConsoleOutputCP(65001);

    if (argc == 1) {
        std::cerr << "Error: Alphabet file not specified\n";
        return 1;
    }

    std::unordered_map <wchar_t, int> alphabet;
    std::wifstream alphabet_file(argv[1]);

    if (!alphabet_file) {
        std::cerr << "Error: Alphabet file not found\n";
        return 1;
    }

    if (alphabet_file.is_open()) {
        wchar_t ch;
        while (alphabet_file.get(ch)) {
            if (alphabet.find(ch) != alphabet.end())
                alphabet[ch] = alphabet[ch] + 1;
            else
                alphabet.insert(std::make_pair(ch, 1));
        }
    }

    for (auto i = alphabet.begin(); i != alphabet.end(); i++) {
        if (i->first == '\n')
            std::wcout << "\\n" << ": " << i->second << std::endl;
        else
            std::wcout << i->first << ": " << i->second << std::endl;
    }

    alphabet_file.close();

    return 0;
}


Вот как программа читает английский файл:
65d34fa5d4aa6193661044.png

А вот как русский файл:
65d34fe329449399759234.png

Вот какой первый символ хранит в себе unordered_map, хотя должен был хранить символ русской буквы "З".
65d34f01af165602423802.png

Все текста сохранены в обчном файле с форматом .txt в UTF-8. Пробовал менять на UTF-16, но и это не помогло. Вообще нет представления о том, как это починить :(
  • Вопрос задан
  • 910 просмотров
Пригласить эксперта
Ответы на вопрос 4
AshBlade
@AshBlade
Просто хочу быть счастливым
Попробуй указать локаль - setlocale(LC_ALL, "Russian");
Ответ написан
@dima20155
you don't choose c++. It chooses you
Используйте std::wstring в качестве ключа.
https://godbolt.org/z/sfTq4nPhj

#include <iostream>
#include <unordered_map>
#include <cwchar>

int main() {
    // Define a wide character string
    std::wstring key1 = L"бла_бла";
    std::unordered_map<std::wstring, int> mp;
    
    mp[L"бла_бла"] = 42;
    std::cout << mp[key1];

    return 0;
}


Для вывода в консоль установите локаль + либу, чтобы нормально итерироваться по строке. Например, вот либа для UTF-8 https://github.com/nemtrif/utfcpp
Ответ написан
Vapaamies
@Vapaamies
Разработчик будущей ОС для ПК размером 250 МБ
Локаль тут вообще не причем, если исходный файл в UTF-8 или UTF-16.

Файл надо считывать в память целиком. Если в UTF-8 — преобразовывать в UTF-16, чтобы получить те самые wchar, потом использовать их как ключи.
Ответ написан
alex1951
@alex1951
"умных преподавателей слушал я невнимательно..."
Сделайте так:
setlocale(LC_ALL, "ru-RU.UTF8");

    if (argc == 1) {
        std::cerr << "Error: Alphabet file not specified\n";
        return 1;
    }

    std::unordered_map <wchar_t, int> alphabet;
    std::wifstream alphabet_file(argv[1]);

    if (!alphabet_file) {
        std::cerr << "Error: Alphabet file not found\n";
        return 1;
    }
    alphabet_file.imbue(std::locale("ru-RU.UTF8"));

дальше Ваш код. И все будет норм( если, конечно, и файл .cpp и входной файл в кодировке UTF-8)
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы