C ++中宽字符的问题

时间:2017-02-06 03:22:01

标签: c++ wstring wchar

我有一个程序,用于读取单词的文本文件(每个单独的行),然后打印出该文件中的随机单词。它还使您能够选择非英语语言(例如,希腊语或俄语)。由于后一种情况,我使用std::wstring来捕获文本。这是代码:

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <cstdlib>
#include <boost/random/mersenne_twister.hpp>
#include <boost/random/random_device.hpp>
#include <boost/random/uniform_int_distribution.hpp>


int main(int argc, char* argv[]) {
    if (argc != 2) {
        std::cout << "Usage: word [lang]" << std::endl;
        std::cout << "\tlang: Choose from de,en,es,fr,gr,it,la,ru" << std::endl;
        return EXIT_FAILURE;
    }

    std::string file = static_cast<std::string>("C:\\util_bin\\data\\words_") + static_cast<std::string>(argv[1]) + static_cast<std::string>(".txt");
    std::wfstream fin(file, std::wifstream::in);

    std::vector<std::wstring> data;
    std::wstring line;
    while (std::getline(fin, line))
        data.push_back(line);
    int size = data.size();

    boost::random::random_device rd;
    boost::random::mt19937 mt(rd());
    boost::random::uniform_int_distribution<int> dist(0, size - 1);

    std::wcout << data[dist(mt)] << std::endl;
}

这段代码编译得很好,但是当我用俄语(例如)运行它时,我只是得到垃圾文本:

C:\util_bin>word ru
������������

C:\util_bin>

我不是很熟悉C ++中广泛字符的来龙去脉,所以我无法真正辨别出出了什么问题。有人有什么想法吗?

2 个答案:

答案 0 :(得分:2)

我猜你正在使用Visual Studio。这是Windows中definesPresentationContext实现的一个怪癖。来自the relevant MSDN page

  

类型basic_filebuf的对象是使用类型为std::basic_filebuf的内部缓冲区创建的,无论类型参数char *指定的char_type如何。这意味着Unicode字符串(包含Elem个字符)将在写入内部缓冲区之前转换为ANSI字符串(包含char字符)。要在缓冲区中存储Unicode字符串,请创建类型为wchar_t的新缓冲区,并使用wchar_t方法进行设置。

正如我所解释的那样,filebuf是用basic_streambuf::pubsetbuf()实现的;有一个内部标志执行ANSI转换,无论你是否想要它,你无法清除。除了分配和设置自己的缓冲区(通过FILE*)之外的标志。在您的语言环境中放置pubsetbuf将无法执行此操作。它必须在成功打开文件后立即发生。真的,令人愤怒的侵入性。我不得不写一个包装类(这不是很糟糕,因为它让你能够在打开之前存储文件名)。

您也可以使用codecvt打开文件。有些人建议你总是那样做。但是以这种方式打开文件可能会使您在插入流或从中提取之前进行自己的代码转换。

答案 1 :(得分:0)

创建实例化wfstream对象后,请像这样调用imbue

fin.imbue( std::locale(std::locale::empty(), new std::codecvt_utf8<wchar_t>) );