【问题标题】:wcin.imbue and UTF-8wcin.imbue 和 UTF-8
【发布时间】:2015-12-03 00:36:52
【问题描述】:

在使用 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,不是任何单字节编码)。

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

这符合标准吗?难道我不能不考虑全局语言环境而改用imbue 吗?

是否应将所描述的任何一种行为归类为实现错误?

【问题讨论】:

  • 这里的“clang++”是什么意思?编译器无关紧要,因为这完全取决于标准库(C 和 C++ 部分)和机器上安装的语言环境数据。您是否同时检查了 libstdc++ 和 libc++,或者只使用两个编译器检查了 libstdc++ 两次?
  • @JonathanWakely 你是对的,我应该说“libstdc++ 和 libc++”。我想我确实将 libc++ 与 clang++ 一起使用,但我现在无法检查。我一拿到我的机器就会仔细检查和更新。
  • 好的,那么我想知道这个问题是否是wcin的基本限制,因为从UTF-8八位字节到wchar_t的转换是由stdio层完成的,它使用全局语言环境不是流的。但它可能只是 libstdc++ 中的一个错误(也可能是 libc++),我不确定。天真地,我也希望您使用 imbue 能够正常工作。
  • @JonathanWakely 我不确定如何通过 stdio 进行转换。 fstream 实现使用 fread 不应该做任何翻译。
  • @JonathanWakely 事实证明,使用 libc++ neither 分支工作。我会相应地更新问题。

标签: c++ utf-8 g++ locale clang++


【解决方案1】:

首先你应该使用 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) 本地化 locale 和 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++,所以无法测试这种行为,抱歉。

【讨论】:

  • 好的,我知道全局 setlocale 可以与 libstdc++ 一起使用。但是,为什么我们需要与 stdio 不同步才能注入语言环境呢?我在标准中找不到任何内容。
  • 同步允许您在同一程序中使用 cout 和 printf。非语言环境 C 流在与 C++ 流同步时会破坏 utf-8 编码。这就是第二个解决方案使用全局 setlocale 的原因。
  • 但是我没有做任何C流I/O,为什么还需要unsync?
  • 同步流是默认行为
  • 这些是微软的话,不是标准的。虽然我爱微软就像下一个家伙一样,但他们并不完全以严格遵守 C++ 标准而闻名。
猜你喜欢
  • 2020-12-09
  • 2017-05-07
  • 1970-01-01
  • 2011-10-11
  • 2017-05-19
  • 2014-12-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多