【发布时间】:2014-10-15 16:04:30
【问题描述】:
我正在尝试使用 C++11 中的 std::locale 机制来计算不同语言的单词。具体来说,我有std::wstringstream,其中包含着名的俄罗斯小说的标题(英文为“犯罪与惩罚”)。我想要做的是使用适当的语言环境(我的 Linux 机器上的ru_RU.utf8)来读取字符串流,计算单词并打印结果。我还应该注意到我的系统设置为使用en_US.utf8 语言环境。
想要的结果是这样的:
0: "Преступление"
1: "и"
2: "наказание"
I counted 3 words.
and the last word was "наказание"
当我设置全局语言环境时,这一切都有效,但当我尝试 imbue wcout 流时,一切都无效。当我尝试这样做时,我得到了这个结果:
0: "????????????"
1: "?"
2: "?????????"
I counted 3 words.
and the last word was "?????????"
另外,当我尝试使用 cmets 中建议的解决方案时(可以通过将 #define USE_CODECVT 0 更改为 #define USE_CODECVT 1 来激活),我收到了 this other question 中提到的错误。
有兴趣尝试代码或编译器设置或两者的人可能希望使用this live code。
我的问题
- 为什么这不起作用?是因为
wcout已经打开了吗? - 有没有办法使用
imbue而不是设置全局语言环境来做我想做的事?
如果有什么不同,我使用的是 g++ 4.8.3。完整代码如下所示。
getwords.cpp
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <locale>
#define USE_CODECVT 0
#define USE_IMBUE 1
#if USE_CODECVT
#include <codecvt>
#endif
using namespace std;
int main()
{
#if USE_CODECVT
locale ru("ru_RU.utf8",
new codecvt_utf8<wchar_t, 0x10ffff, consume_header>{});
#else
locale ru("ru_RU.utf8");
#endif
#if USE_IMBUE
wcout.imbue(ru);
#else
locale::global(ru);
#endif
wstringstream in{L"Преступление и наказание"};
in.imbue(ru);
wstring word;
unsigned wordcount = 0;
while (in >> word) {
wcout << wordcount << ": \"" << word << "\"\n";
++wordcount;
}
wcout << "\nI counted " << wordcount << " words.\n"
<< "and the last word was \"" << word << "\"\n";
}
【问题讨论】:
-
尝试将 utf8 转换方面安装到语言环境中:
locale ru{"ru_RU.utf8", new std::codecvt_utf8<wchar_t, 0x10ffff, std::consume_header>{}};。这需要<codecvt>标头。 -
不幸的是,这里没有编译。请参阅this question 了解我的确切症状。我不知道使用 g++ 的解决方法。
-
UTF-8 不依赖于语言环境。它可以表示任何语言使用的任何 Unicode 代码点。我认为问题不在于
wcout执行的转换。我会检查两件事。首先,字符串文字是否完整地进入二进制文件。做wcout << (int)L'П';- 这应该打印1055;如果不是,则该字符被编译器破坏。二、控制台是否设置为显示非英文字符。将输出重定向到文件,用十六进制查看器检查它。西里尔文'П'应表示为两个字节D0 9F -
将输出重定向到文件没有区别,并且字符在字符串中正确表示。我在程序
wcout << "The first letter of the last word is U+0" << hex << (int)(word[0]) << " (" << word[0] << ")\n";中添加了一个新的最后一行,它打印The first letter of the last word is U+043d (?) -
@0x499602D2 我更喜欢非 Boost 答案,但我们将不胜感激。