Ответ 1
mbstowcs()
и wcstombs()
необязательно конвертировать в UTF-16 или UTF-32, они конвертируются в wchar_t
и независимо от того, какая кодировка locale wchar_t
. Все локали Windows используют в качестве кодировки два байта wchar_t
и UTF-16, но на других основных платформах используется 4-байтовый wchar_t
с UTF-32 (или даже кодировка не-Unicode для некоторых локалей). Платформа, поддерживающая только однобайтовые кодировки, может даже иметь один байт wchar_t
и кодировка отличается по языку. Поэтому wchar_t
мне кажется плохим выбором для переносимости и Unicode. *
В С++ 11 были введены некоторые лучшие варианты; новые специализации std:: codecvt, новые классы codecvt и новый шаблон, чтобы сделать их для конверсий очень убедительными.
Сначала новый класс шаблонов для использования codecvt - std:: wstring_convert. Создав экземпляр класса std:: wstring_convert, вы можете легко преобразовать строки:
std::wstring_convert<...> convert; // ... filled in with a codecvt to do UTF-8 <-> UTF-16
std::string utf8_string = u8"This string has UTF-8 content";
std::u16string utf16_string = convert.from_bytes(utf8_string);
std::string another_utf8_string = convert.to_bytes(utf16_string);
Чтобы сделать другое преобразование, вам просто нужны разные параметры шаблона, один из которых - грань codecvt. Вот некоторые новые грани, которые легко использовать с wstring_convert:
std::codecvt_utf8_utf16<char16_t> // converts between UTF-8 <-> UTF-16
std::codecvt_utf8<char32_t> // converts between UTF-8 <-> UTF-32
std::codecvt_utf8<char16_t> // converts between UTF-8 <-> UCS-2 (warning, not UTF-16! Don't bother using this one)
Примеры использования:
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>,char16_t> convert;
std::string a = convert.to_bytes(u"This string has UTF-16 content");
std::u16string b = convert.from_bytes(u8"blah blah blah");
Новые специализации std:: codecvt немного сложнее в использовании, поскольку они имеют защищенный деструктор. Чтобы обойти это, вы можете определить подкласс, который имеет деструктор, или вы можете использовать функцию шаблона std:: use_facet для получения существующего экземпляра codecvt. Кроме того, проблема с этими специализациями заключается в том, что вы не можете использовать их в Visual Studio 2010, поскольку специализация шаблонов не работает с типами typedef'd и что компилятор определяет char16_t и char32_t как typedefs. Вот пример определения вашего собственного подкласса codecvt:
template <class internT, class externT, class stateT>
struct codecvt : std::codecvt<internT,externT,stateT>
{ ~codecvt(){} };
std::wstring_convert<codecvt<char16_t,char,std::mbstate_t>,char16_t> convert16;
std::wstring_convert<codecvt<char32_t,char,std::mbstate_t>,char32_t> convert32;
Специализация char16_t преобразует UTF-16 и UTF-8. Специализация char32_t, UTF-32 и UTF-8.
Обратите внимание, что эти новые конверсии, предоставляемые С++ 11, не включают никакой возможности прямого преобразования между UTF-32 и UTF-16. Вместо этого вам просто нужно объединить два экземпляра std:: wstring_convert.
***** Я подумал, что добавлю примечание к wchar_t и его цель, чтобы подчеркнуть, почему его вообще не следует использовать для Unicode или переносимого интернационализированного кода. Следующая короткая версия моего ответа fooobar.com/questions/22304/...
Что такое wchar_t?
wchar_t определяется таким образом, что любое языковое кодирование char может быть преобразовано в wchar_t, где каждый wchar_t представляет собой ровно одну кодовую точку:
Тип wchar_t - это отдельный тип, значения которого могут представлять собой отдельные коды для всех членов самого большого расширенного набора символов, указанного среди поддерживаемых локалей (22.3.1). - [basic.fundamental] 3.9.1/5
Это не требует, чтобы wchar_t был достаточно большим, чтобы представлять любой символ из всех локалей одновременно. То есть кодировка, используемая для wchar_t, может различаться между локалями. Это означает, что вы не можете преобразовать строку в wchar_t с помощью одного языка, а затем преобразовать обратно в char с помощью другого языкового стандарта.
Поскольку это, по-видимому, основное применение на практике для wchar_t, вы можете задаться вопросом, для чего это полезно, если не это.
Первоначальное намерение и цель wchar_t заключалось в том, чтобы упростить обработку текста, определяя его таким образом, чтобы оно требовало сопоставления "один к одному" от строковых кодовых единиц к текстовым символам, что позволяло использовать одни и те же простые алгоритмы с строками ascii для работы с другими языками.
К сожалению, требования к wchar_t предполагают взаимно однозначное сопоставление между символами и кодовыми точками для достижения этого. Unicode нарушает это предположение, поэтому вы не можете безопасно использовать wchar_t для простых текстовых алгоритмов.
Это означает, что портативное программное обеспечение не может использовать wchar_t как общее представление для текста между локалями или для использования простых текстовых алгоритмов.
Какое использование wchar_t сегодня?
В любом случае, для портативного кода не так много. Если __STDC_ISO_10646__
определено, то значения wchar_t непосредственно представляют кодовые точки Unicode с одинаковыми значениями во всех локалях. Это делает безопасным повторение межобластных преобразований, упомянутых ранее. Однако вы не можете полагаться только на это, чтобы решить, что вы можете использовать wchar_t таким образом, потому что, хотя большинство платформ unix определяют его, Windows даже не работает, хотя Windows использует один и тот же локаль wchar_t во всех локалях.
Причина, по которой Windows не определяет __STDC_ISO_10646__
Я думаю, это потому, что Windows использует UTF-16 в качестве кодировки wchar_t, а потому, что UTF-16 использует суррогатные пары для представления кодовых точек больше U + FFFF, что означает, что UTF-16 не удовлетворяет требованиям для __STDC_ISO_10646__
.
Для специфичного для платформы кода wchar_t может быть более полезным. Это по существу требуется для Windows (например, некоторые файлы просто не могут быть открыты без использования имен файлов wchar_t), хотя Windows является единственной платформой, где это правда, насколько я знаю (так что, возможно, мы можем думать о wchar_t как "Windows_char_t" ).
В hindsight wchar_t явно не полезен для упрощения обработки текста или для хранения независимого от языка текста. Портативный код не должен пытаться использовать его для этих целей.