Pie*_*o M 3 locale cout multiplatform utf-8 wstring
是否可以在不使用平台特定功能的情况下打印UTF-8字符串?
#include <iostream>
#include <locale>
#include <string>
using namespace std;
int main()
{
ios_base::sync_with_stdio(false);
wcout.imbue(locale("en_US.UTF-8")); // broken on Windows (?)
wstring ws1 = L"Wide string.";
wstring ws2 = L"Wide string with special chars \u20AC"; // Euro character
wcout << ws1 << endl;
wcout << ws2 << endl;
wcout << ws1 << endl;
}
Run Code Online (Sandbox Code Playgroud)
我收到此运行时错误:
在抛出'std :: runtime_error'的实例后调用终止
what():locale :: facet :: _ S_create_c_locale名称无效
如果我删除该行wcout.imbue(locale("en_US.UTF-8"));,我只会ws1打印一次.
在另一个问题(" 我怎么能cin和cout一些unicode文本? ")中,Philipp写道:"wcin和wcout在Windows上不起作用,就像等效的C函数一样.只有原生API可以工作." MinGW也是真的吗?
谢谢你的提示!
平台:
MinGW/GCC
Windows 7
我没有在Windows上的mingw环境中使用gcc,但从我收集它不支持C++语言环境.
由于它不支持C++语言环境,因此这并不是真正相关,但是FYI,Windows并不像大多数其他平台那样使用相同的语言环境命名方案.它们使用类似的language_country.encoding,但语言和国家/地区不是代码,编码是Windows代码页编号.因此,语言环境将是"English_United States.65001",但这不是受支持的组合(代码页65001(UTF-8)不支持作为任何语言环境的一部分).
仅ws1打印的原因是,只有一次\u20AC打印字符时,流失败并设置失败位.在进一步打印之前,您必须清除错误.
C++ 11引入了一些可以轻松处理UTF-8的东西,但并不是所有东西都支持,并且这些内容并没有完全解决问题.但现在的情况是:
当char16_t和char32_t在VS被支撑作为本机类型,而不是类型定义,你将能够使用标准的codecvt面特codecvt<char16_t,char,mbstate_t>和codecvt<char32_t,char,mbstate_t>所需要分别UTF-16或UTF-32之间进行转换,和UTF-8 (而不是执行字符集或系统编码).这还不行,因为在当前的VS(和VS11DP)中,这些类型只是typedef,模板特化不适用于typedef,但代码已经在VS 2010的标题中,只是受到保护#ifdef.
该标准还定义了一些支持的特殊用途codecvt facet模板,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";
Run Code Online (Sandbox Code Playgroud)
这将通过附加到wcout的任何内容输出UTF-8代码单元.如果输出已重定向到文件,则打开它将显示UTF-8编码文件.但是,由于Windows上的控制台模型以及标准流的实现方式,您无法通过这种方式在命令提示符中正确显示Unicode字符(即使您将控制台输出代码页设置为UTF-8 SetConsoleOutputCP(CP_UTF8)) .UTF-8代码单元一次输出一个,并且控制台将查看传递给它的每个单独的块,期望传递的每个块(即,在这种情况下为单个字节)是完整且有效的编码.当显示字符串时,块中的不完整或无效序列(在这种情况下,所有多字节字符表示的每个字节)将被替换为U + FFFD.
如果不是使用iostream,而是使用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());
Run Code Online (Sandbox Code Playgroud)
上面的内容仍然不太可移植,因为它假设wchar_t是UTF-16,在Windows上就是这种情况,但在大多数其他平台上都没有,并且标准不要求它.(事实上,我的理解是它在技术上并不符合,因为UTF-16需要多个代码单元来表示某些字符,并且标准要求所选编码中的所有字符必须能够在单个wchar_t中表示).
std::wstring_convert<std::codecvt_utf8<wchar_t>,wchar_t> convert;
Run Code Online (Sandbox Code Playgroud)
以上将可以轻松处理UCS-4和USC-2,但在使用UTF-16的平台上不能在Basic Multilingual Plane之外工作.
您可以使用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;
Run Code Online (Sandbox Code Playgroud)
或者只是使用预处理器宏来定义适当的typedef,如果您的编码标准允许宏.
| 归档时间: |
|
| 查看次数: |
3705 次 |
| 最近记录: |