在Windows控制台应用程序中输出unicode字符串

And*_*rew 68 c++ unicode iostream windows-console

嗨,我试图将unicode字符串输出到带有iostreams的控制台并失败.

我发现了这一点: 在c ++控制台应用程序中使用unicode字体 ,这个代码片段有效.

SetConsoleOutputCP(CP_UTF8);
wchar_t s[] = L"èéøÞ????æ?a";
int bufferSize = WideCharToMultiByte(CP_UTF8, 0, s, -1, NULL, 0, NULL, NULL);
char* m = new char[bufferSize]; 
WideCharToMultiByte(CP_UTF8, 0, s, -1, m, bufferSize, NULL, NULL);
wprintf(L"%S", m);
Run Code Online (Sandbox Code Playgroud)

但是,我没有找到任何方法来使用iostream正确输出unicode.有什么建议?

这不起作用:

SetConsoleOutputCP(CP_UTF8);
utf8_locale = locale(old_locale,new boost::program_options::detail::utf8_codecvt_facet());
wcout.imbue(utf8_locale);
wcout << L"¡Hola!" << endl;
Run Code Online (Sandbox Code Playgroud)

编辑 我找不到任何其他解决方案,而不是在流中包装此片段.希望,有人有更好的想法.

//Unicode output for a Windows console 
ostream &operator-(ostream &stream, const wchar_t *s) 
{ 
    int bufSize = WideCharToMultiByte(CP_UTF8, 0, s, -1, NULL, 0, NULL, NULL);
    char *buf = new char[bufSize];
    WideCharToMultiByte(CP_UTF8, 0, s, -1, buf, bufSize, NULL, NULL);
    wprintf(L"%S", buf);
    delete[] buf; 
    return stream; 
} 

ostream &operator-(ostream &stream, const wstring &s) 
{ 
    stream - s.c_str();
    return stream; 
} 
Run Code Online (Sandbox Code Playgroud)

Duc*_*tro 82

我在这里使用Visual Studio 2010验证了一个解决方案.通过这篇MSDN文章MSDN博客文章.诀窍是一个模糊的调用_setmode(..., _O_U16TEXT).

解:

#include <iostream>
#include <io.h>
#include <fcntl.h>

int wmain(int argc, wchar_t* argv[])
{
    _setmode(_fileno(stdout), _O_U16TEXT);
    std::wcout << L"Testing unicode -- English -- ???????? -- Español." << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

截图:

控制台中的Unicode

  • 当你还有std :: cout时不起作用 (11认同)
  • `当你还有std :: cout的时候不起作用.来自cplusplus.com:程序不应该将wcout上的输出操作与cout上的输出操作混合(或者与stdout上的其他窄导向输出操作混合):一次输出操作已经执行过任何一个,标准输出流获取一个方向(窄或宽),只能通过在stdout上调用freopen来安全地更改. (10认同)
  • 它仍然不会在我的控制台中显示日语字符. (6认同)
  • +1并删除了我的答案.这是我们为[Instalog]选择的方法(https://bitbucket.org/BillyONeal/instalog/src/1bbf83ca2d1c/Instalog/Main.cpp#cl-49). (4认同)
  • +1 对于有效的修复,**但是**应该注意,这是一种 VIsual C++ 特定的解决方案:它不一定适用于 g++。 (2认同)
  • 在处理答案中的字符串时,它不适用于较长的字符,例如`L"안녕하세요."`或`L"你好!"`。看来,默认控制台字体不支持这些(这可能取决于 Windows 中的区域设置)。 (2认同)

vit*_*aut 24

在 C++23 中,您将能够用于可std::print移植地打印 Unicode 文本:

\n
import std;\n\nint main() {\n  std::print("\xd0\xa8\xd1\x87\xd1\x83\xd1\x87\xd1\x8b\xd0\xbd\xd1\x88\xd1\x87\xd1\x8b\xd0\xbd\xd0\xb0");\n}\n
Run Code Online (Sandbox Code Playgroud)\n

输出:

\n
\xd0\xa8\xd1\x87\xd1\x83\xd1\x87\xd1\x8b\xd0\xbd\xd1\x88\xd1\x87\xd1\x8b\xd0\xbd\xd0\xb0\n
Run Code Online (Sandbox Code Playgroud)\n

这需要使用/utf-8MSVC中的编译器选项进行编译。

\n

在它可用之前,您可以使用基于开源的 {fmt} 库std::print。例如:

\n
\xd0\xa8\xd1\x87\xd1\x83\xd1\x87\xd1\x8b\xd0\xbd\xd1\x88\xd1\x87\xd1\x8b\xd0\xbd\xd0\xb0\n
Run Code Online (Sandbox Code Playgroud)\n

我不建议使用,wcout因为它是不可移植的,如果不付出额外的努力,甚至无法在 Windows 上运行,例如:

\n
#include <fmt/core.h>\n\nint main() {\n  fmt::print("\xd0\xa8\xd1\x87\xd1\x83\xd1\x87\xd1\x8b\xd0\xbd\xd1\x88\xd1\x87\xd1\x8b\xd0\xbd\xd0\xb0");\n}\n
Run Code Online (Sandbox Code Playgroud)\n

将打印:

\n
\xe2\x94\x9c\xd0\xb8\xe2\x94\x9c\xd0\xb9\xe2\x94\x9c\xe2\x95\x95\xe2\x94\x9c\xd0\xae\xe2\x95\x9f\xe2\x95\x9c\xe2\x95\xa8\xe2\x95\x97\xe2\x95\xa4\xd0\xa9\xe2\x95\xac\xd0\xb3\xe2\x94\x9c\xd0\xb6\xe2\x94\x80\xd0\x9da\n
Run Code Online (Sandbox Code Playgroud)\n

在西里尔文 Windows 中(ACP 1251,控制台 CP 866)。

\n

免责声明:我是 {fmt} 和 C++23 的作者std::print

\n


Dav*_*vid 6

中文Unicode Hello World

这是中文的世界。其实只是“你好”。我在Windows 10上对此进行了测试,但是我认为自Windows Vista起它可能会起作用。在Windows Vista之前,如果您需要编程解决方案,而不是配置控制台/注册表等,将很难。如果您确实需要在Windows 7上执行此操作,请查看此处: 更改控制台字体Windows 7

我不想声称这是唯一的解决方案,但这对我有用。

大纲

  1. Unicode项目设置
  2. 将控制台代码页设置为unicode
  3. 查找并使用支持您要显示的字符的字体
  4. 使用您要显示的语言的语言环境
  5. 使用宽字符输出,即 std::wcout

1项目设置

我正在使用Visual Studio 2017 CE。我创建了一个空白的控制台应用程序。可以使用默认设置。但是,如果您遇到问题或使用其他想法,则可能需要检查以下问题:

在项目属性中,找到配置属性->常规->项目默认值->字符集。它应该是“使用Unicode字符集”,而不是“多字节”。这将为您定义_UNICODEUNICODE预处理器宏。

int wmain(int argc, wchar_t* argv[])
Run Code Online (Sandbox Code Playgroud)

另外我认为我们应该使用wmain函数而不是main。它们都可以工作,但是在unicode环境中wmain可能更方便。

我的源文件也是UTF-16-LE编码的,这似乎是Visual Studio 2017中的默认文件。

2.控制台代码页

这是很明显的。我们需要控制台中的unicode代码页。如果要检查默认代码页,只需打开控制台并输入chcp任何参数即可。我们必须将其更改为65001,这是UTF-8代码页。Windows代码页标识符代码页有一个预处理程序宏:CP_UTF8。我需要设置输入和输出代码页。当我省略任何一个时,输出是不正确的。

SetConsoleOutputCP(CP_UTF8);
SetConsoleCP(CP_UTF8);
Run Code Online (Sandbox Code Playgroud)

您可能还需要检查这些函数的布尔返回值。

3.选择一种字体

到目前为止,我还没有找到支持每个字符的控制台字体。所以我不得不选择一个。如果您要输出部分仅以一种字体提供而部分以另一种字体提供的字符,那么我认为找不到解决方案。仅当那里有支持每个字符的字体时,才可能。但是我也没有研究如何安装字体。

我认为不可能在同一控制台窗口中同时使用两种不同的字体。

如何找到兼容的字体?打开控制台,单击窗口左上角的图标,转到控制台窗口的属性。转到字体选项卡,然后选择一种字体,然后单击确定。然后尝试在控制台窗口中输入您的字符。重复此过程,直到找到可以使用的字体。然后记下字体名称。

您也可以在属性窗口中更改字体的大小。如果找到满意的尺寸,请记下在属性窗口中“所选字体”部分中显示的尺寸值。它将以像素为单位显示宽度和高度。

要以编程方式实际设置字体,请使用:

CONSOLE_FONT_INFOEX fontInfo;
// ... configure fontInfo
SetCurrentConsoleFontEx(hConsole, false, &fontInfo);
Run Code Online (Sandbox Code Playgroud)

有关详细信息,请参见此答案末尾的示例。或者在精美的手册中找到它:SetCurrentConsoleFont。从Windows Vista开始,此功能才存在。

4.设置地区

您需要将语言环境设置为您要打印的字符的语言的语言环境。

char* a = setlocale(LC_ALL, "chinese");
Run Code Online (Sandbox Code Playgroud)

返回值很有趣。它将包含一个字符串,以准确描述选择的语言环境。尝试一下:-)我用chinese和测试过german。更多信息:setlocale

5.使用宽字符输出

这里没有太多要说的。如果要输出宽字符,请使用此示例:

std::wcout << L"??" << std::endl;
Run Code Online (Sandbox Code Playgroud)

哦,别忘了L宽字符的前缀!并且,如果您在源文件中键入像这样的文字unicode字符,则源文件必须是unicode编码的。就像Visual Studio中的默认值是UTF-16-LE。或者也许使用notepad ++并将编码设置为UCS-2 LE BOM

最后,我将其全部作为一个示例:

#include <Windows.h>
#include <iostream>
#include <io.h>
#include <fcntl.h>
#include <locale.h>
#include <wincon.h>

int wmain(int argc, wchar_t* argv[])
{
    SetConsoleTitle(L"My Console Window - ??");
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);

    char* a = setlocale(LC_ALL, "chinese");
    SetConsoleOutputCP(CP_UTF8);
    SetConsoleCP(CP_UTF8);

    CONSOLE_FONT_INFOEX fontInfo;
    fontInfo.cbSize = sizeof(fontInfo);
    fontInfo.FontFamily = 54;
    fontInfo.FontWeight = 400;
    fontInfo.nFont = 0;
    const wchar_t myFont[] = L"KaiTi";
    fontInfo.dwFontSize = { 18, 41 };
    std::copy(myFont, myFont + (sizeof(myFont) / sizeof(wchar_t)), fontInfo.FaceName);

    SetCurrentConsoleFontEx(hConsole, false, &fontInfo);

    std::wcout << L"Hello World!" << std::endl;
    std::wcout << L"??!" << std::endl;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

干杯!


cal*_*eve 0

我认为没有一个简单的答案。查看控制台代码页SetConsoleCP 函数, 您似乎需要为要输出的字符集设置适当的代码页。


归档时间:

查看次数:

64523 次

最近记录:

6 年,6 月 前