Я не использовал gcc в среде mingw в Windows, но, насколько я понимаю, он не поддерживает локали C ++.
Так как он не поддерживает локали C ++, это не очень актуально, но, к вашему сведению, Windows не использует ту же схему именования локалей, что и большинство других платформ. Они используют аналогичную language_country.encoding, но язык и страна не являются кодами, а кодировка - это номер кодовой страницы Windows. Таким образом, языковым стандартом будет «English_United States.65001», однако это не поддерживаемая комбинация (кодовая страница 65001 (UTF-8) не поддерживается как часть какого-либо языкового стандарта).
Причина, по которой печатается только ws1
, и только один раз, заключается в том, что при печати символа \u20AC
происходит сбой потока и устанавливается бит сбоя. Вы должны устранить ошибку, прежде чем что-либо будет напечатано.
C ++ 11 представил некоторые вещи, которые будут иметь дело с UTF-8, но пока не все поддерживается, и дополнения не полностью решают проблему. Но вот как сейчас обстоят дела:
Когда char16_t
и char32_t
поддерживаются в VS как собственные типы, а не как typedefs, вы сможете использовать стандартные специализации фасетов codecvt codecvt<char16_t,char,mbstate_t>
и codecvt<char32_t,char,mbstate_t>
, которые необходимы для преобразования между UTF-16 или UTF -32 соответственно и UTF-8 (а не кодировка выполнения или кодировка системы). Это пока не работает, потому что в текущей VS (и в VS11DP) эти типы являются только typedefs, а специализации шаблонов не работают с typedefs, но код уже находится в заголовках в VS 2010, просто защищен #ifdef
.
Стандарт также определяет некоторые поддерживаемые шаблоны фасетов codecvt специального назначения, codecvt_utf8 и codecvt_utf8_utf16. Первый преобразует между UTF-8 и UCS-2 или UCS-4 в зависимости от размера используемого вами широкого символа, а второй преобразует между кодовыми единицами UTF-8 и UTF-16 независимо от размера широкого символа. типа.
std::wcout.imbue(std::locale(std::locale::classic(),new std::codecvt_utf8_utf16<wchar_t>()));
std::wcout << L"ØÀéîðüýþ\n";
Это выведет кодовые единицы UTF-8 через все, что подключено к wcout. Если вывод был перенаправлен в файл, то при открытии он покажет файл в кодировке UTF-8. Однако , из-за модели консоли в Windows и способа реализации стандартных потоков, вы не получите правильное отображение символов Unicode в командной строке таким образом (даже если вы установите кодовую страницу вывода консоли до UTF-8 с SetConsoleOutputCP(CP_UTF8)
). Модули кода UTF-8 выводятся по одному за раз, и консоль будет просматривать каждый отдельный передаваемый ей чанк, ожидая, что каждый переданный чанк (т.е. в данном случае один байт) будет полным и действительным кодированием. Неполные или недопустимые последовательности в чанке (в этом случае каждый байт всех многобайтовых символьных представлений) будут заменены на U + FFFD.
Если вместо использования iostreams вы используете функцию C puts
для записи всей строки в кодировке UTF-8 (и если кодовая страница вывода консоли установлена правильно), то вы можете напечатать строку UTF-8 и получить ее отображается в консоли. Для этого можно использовать те же аспекты codecvt с некоторыми другими классами C ++ 11:
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>,wchar_t> convert;
puts(convert(L"ØÀéîðüýþ\n).to_bytes().c_str());
Выше все еще не вполне переносимо, поскольку предполагается, что wchar_t - это UTF-16, что имеет место в Windows, но не на большинстве других платформ, и это не требуется стандартом. (На самом деле я понимаю, что это технически не соответствует, потому что UTF-16 требуется несколько единиц кода для представления некоторых символов, а стандарт требует, чтобы все символы в выбранной кодировке были представлены в одном wchar_t).
std::wstring_convert<std::codecvt_utf8<wchar_t>,wchar_t> convert;
Вышеуказанное будет переносимо для UCS-4 и USC-2, но не будет работать вне Базовой многоязычной плоскости на платформах, использующих UTF-16.
Вы можете использовать черту типа conditional
для выбора между этими двумя аспектами в зависимости от размера wchar_t
и получить то, что в основном работает:
std::wstring_convert<
std::conditional<sizeof(wchar_t)==2,std::codecvt_utf8_utf16<wchar_t>,
std::codecvt_utf8<wchar_t>
>::type,
wchar_t
> convert;
Или просто используйте макросы препроцессора для определения соответствующего typedef, если ваши стандарты кодирования допускают макросы.