wcin.imbue 和 UTF-8

wcin.imbue and UTF-8

在使用 g++ 的 linux 上,如果我设置了 utf8 全局语言环境,则 wcin 会正确地将 UTF-8 转码为内部 wchar_t 编码。

但是,如果我使用经典语言环境并将 UTF8 语言环境注入 wcin,则不会发生这种情况。输入要么完全失败,要么每个单独的字节都独立地转换为 wchar_t。

使用 clang++ 和 libc++,无论是设置全局语言环境还是在 wcin 中注入语言环境都行不通。

#include <iostream>
#include <locale>
#include <string>

using namespace std;

int main() {
    if(true)        
        // this works with g++, but not with clang++/libc++
        locale::global(locale("C.UTF-8"));
    else
        // this doesn't work with either implementation
        wcin.imbue(locale("C.UTF-8"));
    wstring s;
    wcin >> s;
    cout << s.length() << " " << (s == L"áéú");
    return 0;
}

输入流仅包含 áéú 字符。 (它们是 UTF-8,而不是任何单字节编码)。

现场演示:one two(我无法使用在线编译器重现其他行为)。

这符合标准吗?我不应该单独使用全局语言环境并使用 imbue 吗?

是否应将所描述的行为归类为实施错误?

首先你应该使用 wcout 和 wcin。

现在您有两种可能的解决方案:

1) 使用

停用 iostream 和 cstdio 流的同步
   ios_base::sync_with_stdio(false);

注意,这应该是第一次调用,否则行为取决于实现。

int main() {

   ios_base::sync_with_stdio(false);
   wcin.imbue(locale("C.UTF-8"));

   wstring s;
   wcin >> s;
   wcout << s.length() << " " << (s == L"áéú");
   return 0;
}

2) 本地化语言环境和 wcout:

int main() {

   std::setlocale(LC_ALL, "C.UTF-8");
   wcout.imbue(locale("C.UTF-8"));

    wstring s;
    wcin >> s;
    wcout << s.length() << " " << (s == L"áéú");
    return 0;
}

使用ideone测试了他们两个,工作正常。我没有随身携带 clang++/libc++,所以无法测试此行为,抱歉。