简体   繁体   English

wostream 无法输出 wstring

[英]wostream fails to output wstring

I am using Visual Studio C++ 2008 (Express).我正在使用 Visual Studio C++ 2008 (Express)。 When I run the below code, the wostream (both std::wcout , and std::wfstream ) stops outputting at the first non-ASCII character (in this case Chinese) encountered.当我运行以下代码时,wostream(包括std::wcoutstd::wfstream )在遇到的第一个非 ASCII 字符(在本例中为中文)停止输出。 Plain ASCII characters print fine.纯 ASCII 字符打印正常。 However, in the debugger, I can see that the wstring s are in fact properly populated with Chinese characters, and the output << ... is in fact getting executed.但是,在调试器中,我可以看到wstring实际上正确填充了中文字符,并且output << ...实际上正在执行。

The project settings in the Visual Studio solution are set to "Use Unicode Character Set". Visual Studio 解决方案中的项目设置设置为“使用 Unicode 字符集”。 Why is std::wostream failing to output Unicode characters outside of the ASCII range?为什么std::wostream无法输出 ASCII 范围之外的 Unicode 字符?

void PrintTable(const std::vector<std::vector<std::wstring>> &table, std::wostream& output) {
    for (unsigned int i=0; i < table.size(); ++i) {
        for (unsigned int j=0; j < table[i].size(); ++j) {
            output << table[i][j] << L"\t";
        }
        //output << std::endl;
    }
}


void TestUnicodeSingleTableChinesePronouns() {
    FileProcessor p("SingleTableChinesePronouns.docx");
    FileProcessor::iterator fileIterator;
    std::wofstream myFile("data.bin", std::ios::out | std::ios::binary);
    for(fileIterator = p.begin(); fileIterator != p.end(); ++fileIterator) {
        PrintTable(*fileIterator, myFile);
        PrintTable(*fileIterator, std::wcout);
        std::cout<<std::endl<<"---------------------------------------"<<std::endl;
    }
    myFile.flush();
    myFile.close();
}

By default the locale that std::wcout and std::wofstream use for certain operations is the "C" locale, which is not required to support non-ascii characters (or any character outside C++'s basic character set).默认情况下,std::wcout 和 std::wofstream 用于某些操作的语言环境是“C”语言环境,它不需要支持非 ascii 字符(或 C++ 基本字符集之外的任何字符)。 Change the locale to one that supports the characters you want to use.将区域设置更改为支持您要使用的字符的区域设置。

The simplest thing to do on Windows is unfortunately to use legacy codepages, however you really should avoid that.不幸的是,在 Windows 上要做的最简单的事情是使用旧代码页,但是您确实应该避免这种情况。 Legacy codepages are bad news.遗留代码页是个坏消息。 Instead you should use Unicode, whether UTF-8, UTF-16, or whatever.相反,您应该使用 Unicode,无论是 UTF-8、UTF-16 还是其他。 Also you'll have to work around Windows' unfortunate console model that makes writing to the console very different from writing to other kinds of output streams.此外,您还必须解决 Windows 不幸的控制台模型,该模型使写入控制台与写入其他类型的输出流非常不同。 You might need to find or write your own output buffer that specifically handles the console (or maybe file a bug asking Microsoft to fix it).您可能需要找到或编写自己的输出缓冲区来专门处理控制台(或者提交一个错误,要求 Microsoft 修复它)。

Here's an example of console output:这是控制台输出的示例:

#include <Windows.h>

#include <streambuf>
#include <iostream>

class Console_streambuf
    : public std::basic_streambuf<wchar_t>
{
    HANDLE m_out;
public:
    Console_streambuf(HANDLE out) : m_out(out) {}

    virtual int_type overflow(int_type c = traits_type::eof())
    {
        wchar_t wc = c;
        DWORD numberOfCharsWritten;
        BOOL res = WriteConsoleW(m_out, &wc, 1, &numberOfCharsWritten, NULL);
        (void)res;
        return 1;
    }
};

int main() {
    Console_streambuf out(GetStdHandle(STD_OUTPUT_HANDLE));
    auto old_buf = std::wcout.rdbuf(&out);
    std::wcout << L"привет, 猫咪!\n";
    std::wcout.rdbuf(old_buf); // replace old buffer so that destruction can happen correctly. FIXME: use RAII to do this in an exception safe manner.
}

You can do UTF-8 output to a file like this (although I'm not sure VS2008 supports codecvt_utf8_utf16):您可以将 UTF-8 输出到这样的文件(虽然我不确定 VS2008 是否支持 codecvt_utf8_utf16):

#include <codecvt>
#include <fstream>

int main() {
    std::wofstream myFile("data.bin", std::ios::out | std::ios::binary);
    myFile.imbue(std::locale(myFile.getloc(),new std::codecvt_utf8_utf16<wchar_t>));

    myFile << L"привет, 猫咪!";
}

Include the following header file包含以下头文件

#include <locale>

at the start of main, add the following line.在 main 的开头,添加以下行。

std::locale::global(std::locale("chinese"));

This helps to set the proper locale.这有助于设置正确的语言环境。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM