utfcpp и Win32 широкий API
Хорошо ли / безопасно / возможно использовать крошечную библиотеку utfcpp для преобразования всего, что я получаю от широкого Windows API (FindFirstFileW и тому подобное), в действительное представление UTF8 с использованием utf16to8?
Я хотел бы использовать UTF8 для внутреннего использования, но у меня возникают проблемы с получением правильного вывода (через wcout после другого преобразования или простой cout). Нормальные символы ASCII работают, конечно, но они запутались.
Или есть более легкая альтернатива?
Спасибо!
ОБНОВЛЕНИЕ: Благодаря Гансу (ниже), теперь у меня есть простое преобразование UTF8<->UTF16 через Windows API. Работает двухстороннее преобразование, но в строке UTF8 из строки UTF16 есть некоторые дополнительные символы, которые могут вызвать у меня проблемы позже...). Я поделюсь этим здесь из чистого дружелюбия:))
// UTF16 -> UTF8 conversion
std::string toUTF8( const std::wstring &input )
{
// get length
int length = WideCharToMultiByte( CP_UTF8, NULL,
input.c_str(), input.size(),
NULL, 0,
NULL, NULL );
if( !(length > 0) )
return std::string();
else
{
std::string result;
result.resize( length );
if( WideCharToMultiByte( CP_UTF8, NULL,
input.c_str(), input.size(),
&result[0], result.size(),
NULL, NULL ) > 0 )
return result;
else
throw std::runtime_error( "Failure to execute toUTF8: conversion failed." );
}
}
// UTF8 -> UTF16 conversion
std::wstring toUTF16( const std::string &input )
{
// get length
int length = MultiByteToWideChar( CP_UTF8, NULL,
input.c_str(), input.size(),
NULL, 0 );
if( !(length > 0) )
return std::wstring();
else
{
std::wstring result;
result.resize( length );
if( MultiByteToWideChar(CP_UTF8, NULL,
input.c_str(), input.size(),
&result[0], result.size()) > 0 )
return result;
else
throw std::runtime_error( "Failure to execute toUTF16: conversion failed." );
}
}
2 ответа
В Win32 API уже есть функция для этого, WideCharToMultiByte() с CodePage = CP_UTF8. Спасает вас от необходимости полагаться на другую библиотеку.
Обычно вы не можете использовать результат с wcout. Его вывод идет на консоль, он использует 8-битную OEM-кодировку по устаревшим причинам. Вы можете изменить кодовую страницу с помощью SetConsoleCP(), 65001 - это кодовая страница для UTF-8 (CP_UTF8).
Ваш следующий камень преткновения будет шрифт, который используется для консоли. Вам придется изменить его, но найти шрифт с фиксированной высотой и полным набором глифов для покрытия Unicode будет сложно. Вы увидите, что у вас есть проблема со шрифтом, когда вы получите квадратные прямоугольники на выходе. Вопросительные знаки являются проблемами кодирования.
Почему вы хотите использовать UTF8 внутри? Вы работаете с таким количеством текста, что использование UTF16 создаст необоснованные требования к памяти? Даже если бы это было так, вам, вероятно, все равно лучше использовать широкие символы и решать проблемы с памятью каким-либо другим способом (используя дисковый кеш, лучшие алгоритмы или структуры данных).
Ваш код будет намного чище и проще в использовании, если использовать внутренние символы, встроенные в Win32 API, и выполнять преобразования UTF8 только при чтении или записи нужных данных (например, файлов XML или API REST).
Ваша проблема также может возникать в тот момент, когда вы выводите выходные данные на консоль, см. Вывод строк Unicode в консольном приложении Windows.
Наконец, я не использовал библиотеку utfcpp, но преобразования в UTF8 довольно тривиальны для выполнения с использованием Win32. WideCharToMultiByte
а также MultiByteToWideChar
с CP_UTF8
как кодовая страница. Лично я бы делал одноразовое преобразование и работал с текстом в UTF16, пока не пришло время выводить или переносить его в UTF8, если это необходимо.