0 / 0 / 0
Регистрация: 12.09.2015
Сообщений: 12
|
|
1 | |
Ассоциативный контейнер std::map с кириллицей26.02.2019, 20:45. Показов 3569. Ответов 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
|
|
26.02.2019, 20:45 | |
Ответы с готовыми решениями:
14
Возможно ли создать контейнер std::map, в котором в качестве значения была бы ссылка на std::map? Ассоциативный контейнер типа map Map как не ассоциативный контейнер Emplace в std::map. Как добавить элемент в std::map без копирования? |
16495 / 8988 / 2205
Регистрация: 30.01.2014
Сообщений: 15,603
|
|
26.02.2019, 20:57 | 2 |
Ну так
map - упорядоченный контейнер. Элементы в нем находятся в сортированном порядке.Если строка "пробел" выводится первой, значит лексикографическии она первая. Тут все верно. Можете дать полный, компилируемый пример на котором у вас поведение отличается от ожидаемого? Иначе помочь вам будет гораздо сложнее.
0
|
16495 / 8988 / 2205
Регистрация: 30.01.2014
Сообщений: 15,603
|
|
26.02.2019, 20:58 | 3 |
Нет, не нужно. Тут нужно понимание. Пока что вы только гадаете, отсюда проблемы.
0
|
"C with Classes"
|
||||||
26.02.2019, 20:58 | 4 | |||||
Alexxfiles666, работает:
0
|
16495 / 8988 / 2205
Регистрация: 30.01.2014
Сообщений: 15,603
|
|
26.02.2019, 20:58 | 5 |
del
0
|
16495 / 8988 / 2205
Регистрация: 30.01.2014
Сообщений: 15,603
|
|
26.02.2019, 21:04 | 7 |
Не по теме: Минутка телепатии, автор на самом деле заполнил контейнер к коде, но строку, которую он ищет, получает откуда-то извне. При несовпадении кодировок получаем несовпадение при поиске и возврат end(). Т.е. нужно перестать паниковать и пробовать все подряд, а выяснить * в какой кодировке сохранен файл компилируемого исходника * в какой кодировке приходит строка для поиска Далее эти кодировки нужно привести в соответствие и все заработает.
0
|
_stanislav
|
26.02.2019, 21:07
#8
|
0
|
0 / 0 / 0
Регистрация: 12.09.2015
Сообщений: 12
|
|
26.02.2019, 21:19 [ТС] | 9 |
DrOffset, вы правы! Все так у меня устроено как вы сказали... Приходит строка из переменной string... А как узнать в какой кодировке символ в string-овой переменной?
0
|
16495 / 8988 / 2205
Регистрация: 30.01.2014
Сообщений: 15,603
|
|
26.02.2019, 21:39 | 10 |
0
|
0 / 0 / 0
Регистрация: 12.09.2015
Сообщений: 12
|
|
26.02.2019, 22:55 [ТС] | 11 |
DrOffset, схема такова:
1) я получаю указатель типа [SAFEARRAY *] на двумерный массив - в этом массиве данные, добытые из диапазона ячеек Excel (данные получены с помощью COM-интерфейса IDispatch). Тип каждого элемента двумерного массива - строка типа BSTR. 2) затем я работаю с каждым элементом массива, проделывая с каждым элементом такую операцию: создаю объект _bstr_t из переменной VARIANT (элемента массива типа BSTR). И присваиваю значение объекта _bstr_t переменной string. Так у меня получается строка string. 3)Далее я проверяю строку string на наличие символов русского алфавита, и если нахожу такие символы, то найденный символ ищу в контейнере map... чтобы перекодировать символ в url-вид, изменив исходный символ в переменной string на аналог этого символа в HEX-кодировке. И какую кодировку содержит строка string при всем при этом, как это определить?
0
|
16495 / 8988 / 2205
Регистрация: 30.01.2014
Сообщений: 15,603
|
||||||
26.02.2019, 23:13 | 12 | |||||
![]() Решение
Скорее всего при преобразовании в char * строка получается в кодировке, которая соответствует текущей локали Windows, в русской Windows - это CP1251.
Однако, сам BSTR - это всегда UTF16, поэтому возможно вообще не стоит связываться с преобразованием, а сделать так:
1
|
0 / 0 / 0
Регистрация: 12.09.2015
Сообщений: 12
|
|
27.02.2019, 00:44 [ТС] | 13 |
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
|
16495 / 8988 / 2205
Регистрация: 30.01.2014
Сообщений: 15,603
|
|
27.02.2019, 09:36 | 14 |
Только наоборот. Внутри данные в юникоде, а при получении строки в байтовом диапазоне происходит перекодирование в одну из локальных кодировок (CP1251 в русской windows).
Не совсем; кодировка string-строк, заданных в исходнике, зависит не от setlocale, а от кодировки самого исходника (именно поэтому я про нее упомянул выше). Если ваш файл cpp в кодировке 1251, то и строки, записанные в контейнер через строковые литералы, в ней же. От setlocale зависит то, как вы сможете их увидеть в консоли windows, по историческим причинам выводимая кодировка консоли отличается от остальной локальной кодировки системы и соответствует локальной кодировке для DOS (в русской windows - CP866). В целом вы почти все верно поняли. Остальным стоит брать с вас пример в умении самостоятельно искать информацию.
1
|
0 / 0 / 0
Регистрация: 12.09.2015
Сообщений: 12
|
|
27.02.2019, 23:08 [ТС] | 15 |
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 за введение меня в мир кодировок и таблиц символов. Одной краеугольной темой, в которой я не разбираюсь, стало меньше!
0
|
27.02.2019, 23:08 | |
Помогаю со студенческими работами здесь
15
std::map, std::vector и порядок обхода коллекции Стоит ли очищать в деструкторе std::map , std::vecotor?
Ассоциативный контейнер и шаблонный класс Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |