Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.52/25: Рейтинг темы: голосов - 25, средняя оценка - 4.52
1 / 1 / 0
Регистрация: 12.09.2015
Сообщений: 12

Ассоциативный контейнер std::map с кириллицей

26.02.2019, 20:45. Показов 5168. Ответов 14
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Всем привет! Никак не могу разобраться каким способом решить интересную проблему. В ассоциативном контейнере map<string, string> содержатся элементы типа pair. First-элемент типа pair - символ кириллицы. Second-элемент типа pair - HEX-код символа. Вот пример моего контейнера map:
map<string, string> Hex_decode{ { "А", "%C0" },{ "Б", "%C1" },{ "В", "%C2" },{ "Г", "%C3" },{ "Д", "%C4" },{ "Е", "%C5" },{ " ", "%20" }};
А, Б, В, ... это русские буквы. Последний first-элемент типа pair - пробел.
Мне нужно найти в контейнере map определенный символ. Допустим символ "В". Я ищу так:
Hex_decode.find("В");
Но результат этого выражения - итератор Hex_decode.end(). То есть эта функция-член не может найти символ "В"... Хотя он там есть. Когда я вывожу первый first-элемент типа pair таким образом:
Hex_decode.begin()->first;
То у меня выводится символ пробела. Который вообще последний в списке элементов контейнера. Когда я узнаю размер контейнера, то мне выводится размер 7. То есть будто бы эти все данные добавились. Но функция член begin() возвращает последний элемент почему-то. Кириллицу игнорирует... Но символы кириллицы учитываются, когда узнаешь размер контейнера.

Я установил уже setlocale(LC_CTYPE, "rus"); не помогло. Устанавливал:
SetConsoleCP(1251);
SetConsoleOutputCP(1251);
Тоже не помогло.

Это помогло только при работе с string. То есть если я ищу в контейнере string("абракадабра") нужный мне символ, то у меня находится тот символ кириллицы, который мне нужен. Но с контейнером map непонятки. Подскажите, можно ли решить простенько данную проблему? (PS: уже устанавливал u8 перед first-элементом типа pair (u8"А"), также задавал тип first-элемента как тип wstring, а first-элементы инициализировал так: L"А".
Ничего не помогло. Тут нужно какое-то сложное решение. Подскажите в каком направлении копать.
0
Лучшие ответы (1)
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
26.02.2019, 20:45
Ответы с готовыми решениями:

Возможно ли создать контейнер std::map, в котором в качестве значения была бы ссылка на std::map?
Здравствуйте. Возможно ли создать контейнер std::map, в котором в качестве значения была бы ссылка на std map? Например: std::map...

Ассоциативный контейнер типа map
Привет! Помогите пожалуйста найти ошибку. Программа с Ассоциативным контейнером типа map&lt;string, int&gt;. Прога подсчитывает колличество...

Map как не ассоциативный контейнер
Здравствуйте. Я вложил в контейнер map кучу элементов с ключом String и значением - объектом моего класса (то есть значение получается не...

14
19500 / 10105 / 2461
Регистрация: 30.01.2014
Сообщений: 17,816
26.02.2019, 20:57
Цитата Сообщение от Alexxfiles666 Посмотреть сообщение
То у меня выводится символ пробела.
Ну так map - упорядоченный контейнер. Элементы в нем находятся в сортированном порядке.
Если строка "пробел" выводится первой, значит лексикографическии она первая. Тут все верно.

Цитата Сообщение от Alexxfiles666 Посмотреть сообщение
Кириллицу игнорирует...
Можете дать полный, компилируемый пример на котором у вас поведение отличается от ожидаемого? Иначе помочь вам будет гораздо сложнее.
0
19500 / 10105 / 2461
Регистрация: 30.01.2014
Сообщений: 17,816
26.02.2019, 20:58
Цитата Сообщение от Alexxfiles666 Посмотреть сообщение
Тут нужно какое-то сложное решение.
Нет, не нужно. Тут нужно понимание. Пока что вы только гадаете, отсюда проблемы.
0
"C with Classes"
2022 / 1404 / 523
Регистрация: 16.08.2014
Сообщений: 5,885
Записей в блоге: 1
26.02.2019, 20:58
Alexxfiles666, работает:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
#include <map>
#include <string>
 
int main()
{
    std::map<std::string, std::string> map
    {
        std::make_pair("A", "1"),
        std::make_pair("B", "2"),
        std::make_pair("C", "3"),
    };
 
    auto it = map.find("B");
 
    return 0;
}
локали тут не при чем
0
19500 / 10105 / 2461
Регистрация: 30.01.2014
Сообщений: 17,816
26.02.2019, 20:58
del
0
"C with Classes"
2022 / 1404 / 523
Регистрация: 16.08.2014
Сообщений: 5,885
Записей в блоге: 1
26.02.2019, 20:58
---
0
19500 / 10105 / 2461
Регистрация: 30.01.2014
Сообщений: 17,816
26.02.2019, 21:04

Не по теме:

Минутка телепатии,


автор на самом деле заполнил контейнер к коде, но строку, которую он ищет, получает откуда-то извне. При несовпадении кодировок получаем несовпадение при поиске и возврат end(). Т.е. нужно перестать паниковать и пробовать все подряд, а выяснить
* в какой кодировке сохранен файл компилируемого исходника
* в какой кодировке приходит строка для поиска
Далее эти кодировки нужно привести в соответствие и все заработает.
0
26.02.2019, 21:07

Не по теме:

Цитата Сообщение от DrOffset Посмотреть сообщение
нужно перестать паниковать
утро вечера мудренее, сколько раз с утра задача становилась легче как по волшебству. у меня лично уже не работает место которым нужно думать :)

0
1 / 1 / 0
Регистрация: 12.09.2015
Сообщений: 12
26.02.2019, 21:19  [ТС]
DrOffset, вы правы! Все так у меня устроено как вы сказали... Приходит строка из переменной string... А как узнать в какой кодировке символ в string-овой переменной?
0
19500 / 10105 / 2461
Регистрация: 30.01.2014
Сообщений: 17,816
26.02.2019, 21:39
Цитата Сообщение от Alexxfiles666 Посмотреть сообщение
А как узнать в какой кодировке символ в string-овой переменной?
Ну расскажите, для начала, откуда она приходит.
0
1 / 1 / 0
Регистрация: 12.09.2015
Сообщений: 12
26.02.2019, 22:55  [ТС]
DrOffset, схема такова:
1) я получаю указатель типа [SAFEARRAY *] на двумерный массив - в этом массиве данные, добытые из диапазона ячеек Excel (данные получены с помощью COM-интерфейса IDispatch). Тип каждого элемента двумерного массива - строка типа BSTR.
2) затем я работаю с каждым элементом массива, проделывая с каждым элементом такую операцию: создаю объект _bstr_t из переменной VARIANT (элемента массива типа BSTR). И присваиваю значение объекта _bstr_t переменной string. Так у меня получается строка string.
3)Далее я проверяю строку string на наличие символов русского алфавита, и если нахожу такие символы, то найденный символ ищу в контейнере map... чтобы перекодировать символ в url-вид, изменив исходный символ в переменной string на аналог этого символа в HEX-кодировке.

И какую кодировку содержит строка string при всем при этом, как это определить?
0
19500 / 10105 / 2461
Регистрация: 30.01.2014
Сообщений: 17,816
26.02.2019, 23:13
Лучший ответ Сообщение было отмечено Alexxfiles666 как решение

Решение

Цитата Сообщение от Alexxfiles666 Посмотреть сообщение
строка типа BSTR.
Скорее всего при преобразовании в char * строка получается в кодировке, которая соответствует текущей локали Windows, в русской Windows - это CP1251.

Однако, сам BSTR - это всегда UTF16, поэтому возможно вообще не стоит связываться с преобразованием, а сделать так:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// ваш код
 
std::map<std::wstring, std::string> Hex_decode{ 
 { L"А", "%C0" },{ L"Б", "%C1" },{ L"В", "%C2" },{ L"Г", "%C3" },{ L"Д", "%C4" },{ L"Е", "%C5" },{ L" ", "%20" }
};
 
BSTR bstrText = /*некая строка*/
 
_bstr_t tmp(bstrText);
 
std::wstring fstr((wchar_t *)tmp, tmp.length());
 
if(Hex_decode.find(fstr) != Hex_decode.end())
{
    //.....
}
 
// ваш код
1
1 / 1 / 0
Регистрация: 12.09.2015
Сообщений: 12
27.02.2019, 00:44  [ТС]
DrOffset, спасибо! Покопал в сторону BSTR и _bstr_t. Понял, что класс _bstr_t - оболочка для работы с опасным типом BSTR. Также узнал, что когда я присваиваю переменной string значение объекта _bstr_t, то этот класс _bstr_t внутри себя вызывает функцию ConvertBSTRToString. Соответственно эта функция присваивает созданному временно массиву char * значение объекта _bstr_t...
А BSTR тип это тип OLECHAR *. А Олечар* это тип WCHAR. А символы типа WCHAR глобально имеют кодировку UNICODE. Windows использует кодировку UTF16 для строк типа WCHAR. Ну WCHAR это тоже самое, что и wchar_t... Широкий символ. Грубо говоря, строка типа BSTR оказалась строкой типа wchar_t... И кодировка этой строки - с помощью UTF16. UTF16 берет символы из UNICODE.
Данные из ячейки Excel попадают в строку BSTR. В ячейке Эксель данные - строка в кириллице. Значит ее кодировка - cp1251, а берутся символы из таблицы ASCII. И запихиваются в строку BSTR, которая имеет кодировку UTF16. То есть данные из ячейки эксель закодированы в cp1251, а затем перекодирываются в UTF16... Во время этого действия неизвестно что происходит. Хотя я же считываю нормально данные. Значит перекодирование переменных происходит вроде как гладко.
Затем следующее преобразование из широкого символа в обычный символ char... Тоже что то с данными происходит.

Я проверил - map с типами string string работает. Это я тупил. Значит проблема именно в закодированном символе, который находится внутри переменной string. Он не находит последовательность байт в map. Значит последовательность разная. Это значит, что переменная string владеет символом кириллицы из кодировки Unicode... получается наверное так. А map владеет символами из кодировки cp1251, так как в файле я применил setlocale... Уважаемый DrOffset, вы совершенно правы! Мне надо использовать в map тип широкого символа. Чтобы кириллические символы брались из UNICODE. Ну и соответственно не надо преобразовывать из широкого символа в обычный символ строку-символ BSTR.
Я рассуждаю вслух, чтобы помочь потом кому нибудь в этом. А то все темы о выводе в консоль кириллицы... и ни одной темы про контейнеры с кириллицей... Вот теперь есть такая тема! Я попытался разжевать как смог свою проблему.
0
19500 / 10105 / 2461
Регистрация: 30.01.2014
Сообщений: 17,816
27.02.2019, 09:36
Цитата Сообщение от Alexxfiles666 Посмотреть сообщение
В ячейке Эксель данные - строка в кириллице. Значит ее кодировка - cp1251, а берутся символы из таблицы ASCII. И запихиваются в строку BSTR, которая имеет кодировку UTF16. То есть данные из ячейки эксель закодированы в cp1251, а затем перекодирываются в UTF16...
Только наоборот. Внутри данные в юникоде, а при получении строки в байтовом диапазоне происходит перекодирование в одну из локальных кодировок (CP1251 в русской windows).

Цитата Сообщение от Alexxfiles666 Посмотреть сообщение
А map владеет символами из кодировки cp1251, так как в файле я применил setlocale...
Не совсем; кодировка string-строк, заданных в исходнике, зависит не от setlocale, а от кодировки самого исходника (именно поэтому я про нее упомянул выше). Если ваш файл cpp в кодировке 1251, то и строки, записанные в контейнер через строковые литералы, в ней же.

От setlocale зависит то, как вы сможете их увидеть в консоли windows, по историческим причинам выводимая кодировка консоли отличается от остальной локальной кодировки системы и соответствует локальной кодировке для DOS (в русской windows - CP866).

Цитата Сообщение от Alexxfiles666 Посмотреть сообщение
Я рассуждаю вслух, чтобы помочь потом кому нибудь в этом. А то все темы о выводе в консоль кириллицы... и ни одной темы про контейнеры с кириллицей...
В целом вы почти все верно поняли. Остальным стоит брать с вас пример в умении самостоятельно искать информацию.
1
1 / 1 / 0
Регистрация: 12.09.2015
Сообщений: 12
27.02.2019, 23:08  [ТС]
DrOffset, я перечитал вчерашнее сообщение, я конечно сумасбродно объяснил все... и допустил одну ошибку. Когда строка BSTR преобразовывается в тип char*, то "широкий" тип преобразовывается в обычный тип. Широкий тип wchar_t представлен в кодировке UTF16, сама система кодировки UTF16 кодирует символы UNICOD-а. То есть папа wchar_t - UNICODE. Оттуда берутся последовательности байтов.
Я порылся в настройках проекта Visual Studio - и моментально нашел, что коды символов в программе берутся из UNICODE таблицы. Таким образом контейнер map, в котором кириллица - состоит из символов из UNICODE таблицы.
Переменная string, которая получается путем преобразования строки BSTR (с широкими символами) в тип char*(с обычными символами) - состоит из символов, закодированных с помощью одной из кодировок ANSI. А именно: с помощью кодировки Windows-1251. Но кодировка ANSI берет символы из расширенной таблицы ASCII, имеющей кириллические символы, а также символы английского языка и другие необходимый символы.

UNICODE и ASCII - две разные таблицы. Индексы совпадающих элементов-символов тоже разные. Последовательность единичек и нулей, которые представляют конкретный символ в таблице - тоже разная для одного и того же элемента в таблицах UNICODE и ASCII. При взаимодействии двух переменных, содержащих в себе символы из разных таблиц появляются кракозябры в программе, либо программа работает некорректно, как в моем случае.

Мой map содержит символы из таблицы UNICODE, переменная string содержит символы из таблицы ASCII. А я пытался найти символ из таблицы ASCII в переменной, содержащей символы из таблицы UNICODE. Вот умора. Можно считать, что это совершенно разные данные... Лишь графическое представление одинаковое, а вот внутренняя структура совершенно другая. Внутренняя реализация разная. Я сравнивал пирог с коробкой. Коробка была похожа внешне на пирог. Пирог был похож на коробку... Как-то так. Все уложилось за день по полочкам, решил объяснить на своем примере эту довольно сложную проблему... Хотя теперь она мне такой уже не кажется. Спасибо еще раз DrOffset за введение меня в мир кодировок и таблиц символов. Одной краеугольной темой, в которой я не разбираюсь, стало меньше!
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
27.02.2019, 23:08
Помогаю со студенческими работами здесь

Emplace в std::map. Как добавить элемент в std::map без копирования?
здравствуйте... есть ли способ не писать так: std::map&lt;int, char&gt; ksa; ksa.emplace(std::piecewise_construct, ...

std::map, std::vector и порядок обхода коллекции
Здравствуйте, уважаемые! Вопрос следующий - если я сохраняю какие-то значения в map или вектор, то всегда ли я буду получать тот-же...

Стоит ли очищать в деструкторе std::map , std::vecotor?
У меня ещё один нубский вопрос :) Вот если в классе объявлены мапы и вектора, которые по ходу программы как то заполняются, нужно ли мне...

Std::unordered_multimap<std::string, int> map
Приветствую. Как можно получить только &quot;уникальный&quot; ключ в контейнере? std::unordered_multimap&lt;std::string, int&gt; map; ...

Ассоциативный контейнер и шаблонный класс
Помогите пожалуйста исправить и дополнить код. Задание: Автоматизированная информационная система на железнодорожном вокзале содержит...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
15
Ответ Создать тему
Новые блоги и статьи
Символьное дифференцирование
igorrr37 13.02.2026
/ * Логарифм записывается как: (x-2)log(x^2+2) - означает логарифм (x^2+2) по основанию (x-2). Унарный минус обозначается как ! в-строка - входное арифметическое выражение в инфиксной(обычной). . .
Камера Toupcam IUA500KMA
Eddy_Em 12.02.2026
Т. к. у всяких "хикроботов" слишком уж мелкий пиксель, для подсмотра в ESPriF они вообще плохо годятся: уже 14 величину можно рассмотреть еле-еле лишь на экспозициях под 3 секунды (а то и больше),. . .
И ясному Солнцу
zbw 12.02.2026
И ясному Солнцу, и светлой Луне. В мире покоя нет и люди не могут жить в тишине. А жить им немного лет.
«Знание-Сила»
zbw 12.02.2026
«Знание-Сила» «Время-Деньги» «Деньги -Пуля»
SDL3 для Web (WebAssembly): Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 12.02.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами и вызывать обработчики событий столкновения. . . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 11.02.2026
Содержание блога Библиотека SDL3 содержит встроенные инструменты для базовой работы с изображениями - без использования библиотеки SDL3_image. Пошагово создадим проект для загрузки изображения. . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL3_image
8Observer8 10.02.2026
Содержание блога Библиотека SDL3_image содержит инструменты для расширенной работы с изображениями. Пошагово создадим проект для загрузки изображения формата PNG с альфа-каналом (с прозрачным. . .
Установка Qt-версии Lazarus IDE в Debian Trixie Xfce
volvo 10.02.2026
В общем, достали меня глюки IDE Лазаруса, собранной с использованием набора виджетов Gtk2 (конкретно: если набирать текст в редакторе и вызвать подсказку через Ctrl+Space, то после закрытия окошка. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru