Запутался в std :: wstring, UTF-16, UTF-8 в C ++ и отображении строк в графическом интерфейсе Windows - PullRequest
17 голосов
/ 27 марта 2010

Я работаю над C ++ -программой только для английского языка для Windows, где нам сказали «всегда используйте std :: wstring», но похоже, что никто в команде на самом деле не имеет большого понимания, кроме этого.

Я уже прочитал вопрос под названием "std :: wstring VS std :: string . Это было очень полезно, но я все еще не совсем понимаю, как применить всю эту информацию к моей проблеме.

Программа, над которой я работаю, отображает данные в графическом интерфейсе Windows. Эти данные сохраняются в формате XML. Мы часто преобразуем этот XML с помощью XSLT в HTML или XSL: FO для целей отчетности.

По моим прочтениям, я чувствую, что HTML должен быть закодирован как UTF-8. Я очень мало знаю о разработке графического интерфейса, но то, что я прочитал, указывает на то, что все элементы графического интерфейса основаны на строках в кодировке UTF-16.

Я пытаюсь понять, где это меня оставляет. Скажем, мы решили, что все наши постоянные данные должны быть в кодировке UTF-8. Означает ли это, что для отображения постоянных данных в компоненте пользовательского интерфейса мне действительно нужно выполнить какой-то явный процесс перекодировки UTF-8 в UTF-16?

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

Ответы [ 5 ]

9 голосов
/ 27 марта 2010

Windows начиная с NT4 и более основана на Unicode-кодированных строках, да. Ранние версии были основаны на UCS-2, который является предшественником UTF-16 и, следовательно, не поддерживает все символы, которые поддерживает UTF-16. Более поздние версии основаны на UTF-16. Однако не все ОС основаны на UTF-16 / UCS-2. * Системы nix, например, основаны на UTF-8.

UTF-8 - очень хороший выбор для постоянного хранения данных. Это универсально поддерживаемая кодировка во всех средах Unicode, и это хороший баланс между размером данных и совместимостью данных без потерь.

Да, вам придется анализировать XML, извлекать из него необходимую информацию, декодировать и преобразовывать его в то, что пользовательский интерфейс может использовать.

6 голосов
/ 27 марта 2010

AFAIK, когда вы работаете с std :: wstring в Windows на C ++ и сохраняете с использованием UTF-8 в файлах (что звучит хорошо и разумно), тогда вам нужно преобразовать данные в UTF-8 при записи в файл, и преобразовать обратно в UTF-16 при чтении из файла. Проверьте эту ссылку: Запись файлов UTF-8 на C ++ .

Я бы придерживался Visual Studio по умолчанию проекта -> Свойства -> Свойства конфигурации -> Общие -> Набор символов -> Использовать набор символов Unicode, использовать тип wchar_t (то есть с std :: wstring) и не используйте тип TCHAR. (Например, я бы просто использовал wcslen-версию strlen и , а не _tcslen.)

5 голосов
/ 27 марта 2010

std :: wstring - технически UCS-2: для каждого символа используются два байта, а кодовые таблицы в основном отображаются в формат Unicode. Важно понимать, что UCS-2 - это не то же самое, что UTF-16! UTF-16 допускает «суррогатные пары» для представления символов, которые находятся за пределами двухбайтового диапазона, но UCS-2 использует ровно два байта для каждого символа, точка.

Лучшее правило для вашей ситуации - выполнять перекодирование при чтении и записи на диск. Как только он окажется в памяти, сохраните его в формате UCS-2. API-интерфейсы Windows будут читать его так, как если бы он был UTF-16 (то есть, пока std :: wstring не понимает концепцию суррогатных пар, если вы создаете их вручную (чего не будет, если ваш единственный язык - Англ), винда их прочтет).

Когда бы вы ни читали данные в форматах сериализации или вне их (например, XML) в наше время, вам, вероятно, придется выполнять транскодирование. Это неприятный и очень прискорбный факт из жизни, но он неизбежен, так как Unicode - это кодировка символов переменной ширины, и большинство символьных операций в C ++ выполняются как массивы, для которых вам нужен постоянный интервал.

Инфраструктуры более высокого уровня, такие как .NET, скрывают большинство деталей, но за кадром они обрабатывают транскодирование таким же образом: изменяя данные переменной ширины на строки фиксированной ширины, манипулируя ими, и затем изменяя их обратно в кодировки переменной ширины, когда это требуется для вывода.

3 голосов
/ 27 марта 2010

Одним из преимуществ использования std :: wstring в Windows для строк, связанных с графическим интерфейсом, является то, что внутренне все вызовы Windows API используют и работают в UTF-16. Если вы когда-либо замечали, есть 2 версии всех вызовов Win32 API, которые принимают строковые аргументы. Например, «MessageBoxA» и «MessageBoxW». Оба определения существуют в, и на самом деле вы можете вызывать любое из них, но если оно включено с поддержкой Unicode, произойдет следующее:

#define MessageBox MessageBoxW

Затем вы попадаете на TCHAR и другие хитрости Microsoft, чтобы попытаться упростить работу с API, которые имеют как ANSI, так и Unicode-версию. Короче говоря, вы можете вызывать любой из них, но под капотом ядро ​​Windows на основе Unicode, поэтому вы будете платить за преобразование в Unicode для каждой строки, принимающей вызов Win32 API, если вы не используете версию с широким символом.

Использование ядра UTF-16 и Windows

1 голос
/ 27 марта 2010

Даже если вы говорите, что в ваших данных только английский, вы, вероятно, ошибаетесь. Поскольку сейчас мы находимся в глобальном мире, имена / адреса / и т. Д. Имеют иностранные символы. Хорошо, я не знаю, какой тип данных у вас есть, но в целом я бы сказал, создайте ваше приложение для поддержки UNICODE как для хранения данных, так и для отображения данных пользователю. Это предполагает использование XML с UTF-8 для хранения и UNICODE-версий вызовов Windows, когда вы используете GUI. А поскольку Windows GUI использует UTF-16, где каждый токен является 16-битным, я бы предложил хранить данные в приложении в 16-битной строке. И я полагаю, что для этой цели ваш компилятор для Windows будет использовать std :: wstring как 16-битный.

Итак, вам придется много конвертировать между UTF-16 и UTF-8. Сделайте это с какой-нибудь существующей библиотекой, например, ICU .

...