Как работать с символами Unicode в C++

У нас есть система комментариев, встроенная в наш движок, которая позволяет программистам оставлять комментарии для различных открытых переменных/объектов, которые затем используются внешним интерфейсом GUI для всплывающих подсказок и справки.

Недавно некоторые всплывающие подсказки начали давать сбой, и после того, как я потратил много времени, я отследил его до символа: , который, если я не ошибаюсь, является символом Юникода и недоступен в ASCII.

Принимая во внимание этот ответ, я предположил, что wstring решит проблему. Прежде чем вносить изменения в более крупный проект, я создал тестовый проект, чтобы посмотреть, решит ли wstring проблему. Хотя проект не аварийно завершает работу, поведение wstring отличается от ожидаемого.

#include <iostream>
#include <string>

using namespace std;

int main()
{
    string someString = "successive attack that DOESN’T result";
    wstring someWString = L"successive attack that DOESN’T result";

    cout << someString << endl;
    wcout << someWString << endl;

    return 0;
}

//Console Output//
successive attack that DOESNÆT result 
successive attack that DOESNPress any key to continue . . .

Я прочитал эту статью некоторое время назад и подумал, что понял проблемы, связанные с наборами символов. , но это явно не так. Я был бы признателен за решение этой проблемы, а также за хорошее объяснение того, что происходит и как избежать подобных проблем в будущем.


person Samaursa    schedule 10.02.2012    source источник
comment
Возможно, сам исходный файл не закодирован должным образом. Какая у него кодировка?   -  person Niklas B.    schedule 10.02.2012
comment
Консоль IIRC плохо поддерживает символы, отличные от кодовой страницы. Ваши советы по инструментам работают?   -  person Rup    schedule 10.02.2012
comment
@NiklasB.: Я не уверен, как мне это проверить? Я использую Visual Studio 2008 для создания нового проекта и исходного файла в приведенном выше примере. Я не уверен, как мне проверить кодировку самого исходного файла...? В свойствах проекта я пробовал как Use Multi-byte Character Set, так и Use Unicode Character Set без разницы в выводе.   -  person Samaursa    schedule 10.02.2012
comment
@Rup: мне нужно изменить довольно много кода, чтобы он работал с wstring, поэтому я подумал, что попробую меньший проект, прежде чем вносить изменения и обнаруживать, что они не решают проблему.   -  person Samaursa    schedule 10.02.2012


Ответы (2)


Поскольку вы используете Visual Studio, я предполагаю, что вы используете Windows. Консоль Windows не поддерживает юникод. Он использует набор символов OEM. Вы можете конвертировать между ними, используя CharToOemW/OemToCharW. Очевидно, что он не сможет представить все символы Юникода.

Windows использует UTF16 для своего системного API. Если ваши всплывающие подсказки используют Windows API, вероятно, вы хотите использовать wstring. Однако вместо этого вы можете использовать UTF8 и преобразовать его в UTF16 перед вызовом Windows API. Это преобразование можно выполнить с помощью MultiByteToWideChar/WideCharToMultiByte.

person rasmus    schedule 10.02.2012
comment
Есть ли временное исправление, которое я могу сделать, чтобы получить фиксированную сборку (например, игнорировать символ юникода, как только он встречается)? Затем я начну преобразовывать все строки в wstring (что займет некоторое время). - person Samaursa; 10.02.2012
comment
Если вы пропустите все символы со значением › 127, вы получите только символы ASCII. - person rasmus; 10.02.2012
comment
Что благоприятствует UTF8, так это то, что вы можете продолжать использовать обычные строки, то есть вам не нужно преобразовывать все ваши строки в wstring. Вместо этого вам нужно конвертировать при вызове Unicode (UTF16) Windows API. - person rasmus; 10.02.2012
comment
Я до сих пор что-то путаю. Характер проблемы может быть представлен в переменной char. Он не будет отображаться как , но будет отображаться как Æ... почему это приводит к сбою? Любые предположения относительно того, что может пойти не так в коде при встрече с этим персонажем? - person Samaursa; 10.02.2012
comment
Не зная, как ваш код обрабатывает эти строки, трудно сказать. Возможно, вы можете предоставить больше информации? В общем, этот символ, вероятно, находится за пределами набора символов, который поддерживает ваш код, и не обрабатывает этот случай корректно. Æ — это только интерпретация символа в наборе символов OEM. Вероятно, это не то, что использует ваш код. - person rasmus; 10.02.2012
comment
Согласен, без кода сложно сказать (кодовая база огромна). Я не уверен, какую информацию предоставить, поскольку не могу отследить, где код не работает с символом. Спасибо за помощь/объяснение, так как это помогло мне лучше понять проблему. - person Samaursa; 10.02.2012

Поскольку вы имеете дело с символами Unicode, было бы уместно установить для параметра Набор символов значение Использовать набор символов Unicode в свойствах проекта.

Другой возможной проблемой может быть кодировка исходных файлов. Передовой практикой при работе с символами Unicode является кодировка исходных файлов в UTF-8, особенно файлов, в которых вы определяете строковые литералы, подобные этому. Обратите внимание, что UTF-8 без BOM может быть проблематичным, поскольку Visual Studio нужна эта BOM, чтобы она могла правильно интерпретировать содержимое файлов. Преобразуйте свои файлы (для этого я использую Notepad++) и преобразуйте их так, чтобы они были закодированы в UTF-8.

person LihO    schedule 10.02.2012
comment
Я пробовал то же самое в NPP (сохраняя как UTF-8 или UCS-2) и это не помогает (хотя я использовал сырой cl без VS). Я думаю, проблема в том, что консоль не понимает вывод. - person Niklas B.; 10.02.2012
comment
По моему опыту, если программа использует набор символов Unicode и неправильно отображает строковые литералы, это, скорее всего, связано с плохой кодировкой исходных файлов. - person LihO; 10.02.2012
comment
Да, я думал так же (см. мой комментарий), но я только что попробовал, и это не проблема. - person Niklas B.; 10.02.2012