Скремблирование UTF8 во время загрузки файла c ++ - PullRequest
4 голосов
/ 15 августа 2011

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

У меня есть библиотека графических интерфейсов Win7 / C ++ / DirectX9, которая может отображать текст на экране. У меня никогда раньше не было проблем, поскольку они использовались только с западноевропейским языком. Теперь я должен использовать это с венгерским, и это вызывает у меня головную боль! Моя особая проблема заключается в загрузке специальных символов, найденных на этом языке.

Возьмите этот пример, FELNŐTTEKNEK, что означает ВЗРОСЛЫЙ.

Если я жестко закодирую эту строку в своем приложении, она будет правильно отображаться:

guiTitle->SetText( L"FELNŐTTEKNEK" );

Это сохраняет строку как std :: wstring, представляя ее с помощью ID3DXFont :: DrawTextW (). Это также доказывает, что выбранный мной шрифт Futura CE способен отображать специальные символы (CE = Центрально-Европейский).

Пока все хорошо. Далее я просто хочу иметь возможность загружать текст из текстового файла. Ничего страшного. Однако результаты плохие! Специальный Ő заменяется другим символом, в основном Å или даже двумя символами, например Å (2-й обычно непечатаемый)

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

wifstream f("data/language.ini");
wstring w;  
getline( f, w );    
guiTitle->SetText( w );

Почему-то я все еще карабкаюсь. Я загружаю как UTF-8? Есть ли способ обеспечить это? Мне просто нужно убедиться, что у меня широкая строка с текстом, как показано в текстовом редакторе.

Любая помощь, полученная с благодарностью.

Si

Ответы [ 3 ]

7 голосов
/ 15 августа 2011

Забудьте о wifstream, слишком сложно заставить его работать.Выполните:

ifstream f(L"data/language.ini");
string str;  
getline( f, str );
guiTitle->SetText( utf8_to_utf16(str).c_str() );

И используйте MultiByteToWideChar для реализации utf8_to_utf16.

См. Также https://stackoverflow.com/questions/1049947/should-utf-16-be-considered-harmful.

3 голосов
/ 15 августа 2011

DrawTextW ожидает UTF-16.

Что вы делаете, это конвертируете каждую кодовую единицу UTF-8 (байт) в 16-битное значение, добавляя к нему ноль - это правильно преобразует UTF-8 в UTF-16, только если ваш UTF-8 содержит исключительно символы из Ascii подмножество Unicode.

Что вам нужно сделать, это правильно конвертировать из UTF-8 в UTF-16. Загрузите строку в std :: string (не std :: wstring), затем преобразуйте эту строку UTF-8 в строку UTF-16 и передайте ее API, ожидающему строку UTF-16.

0 голосов
/ 15 августа 2011

Никогда не понимал идею, объявленную там о том, чтобы везде использовать UTF-8, самостоятельно реализовать необходимые функции (что вы также можете сделать и для UTF-16), а затем преобразовать его обратно в UTF-16. при общении с Windows API (и не знаю, как этого избежать проблем с Windows API - в конце концов, вы все равно оставляете ему символы UTF-16 и, следовательно, все равно будете обнаруживать все те же ошибки), кажется, довольно много дополнительной работы для выгоды.

В любом случае, вместо «использовать std :: string и затем преобразовать его, используя низкоуровневые методы в UTF-16», вы можете просто позволить API выполнить свою работу (обратите внимание, что это может не привести к лучшей производительности, у Рэя Чена было несколько серий об этом обратном пути - хотя я надеюсь, что новые компиляторы исправят это и для обычного файла, который вряд ли важен).

В основном вы можете сделать это:

 std::wifstream src;
 src.imbue(std::locale("UTF-8")); // use correct encoding.
 src.open(file);

Почему все работают сами (и каждый раз, когда мне не нужно использовать MultiByteToWideChar, я считаю, что мне повезло), если библиотека может сделать это также - это также делает намерение намного более ясным.

...