如何在控制台打印wchar_t值?

94

例子:

#include <iostream>

using namespace std;

int main()
{
    wchar_t en[] = L"Hello";
    wchar_t ru[] = L"Привет"; //Russian language
    cout << ru
         << endl
         << en;
    return 0;
}

这段代码只打印类似地址的十六进制值。 如何打印wchar_t字符串?


第一个相关问题是http://stackoverflow.com/questions/1625531/c-wchar-to-stdcout-and-comparision。 - anon
1
在哪个操作系统上,使用什么控制台应用程序?有些控制台不支持Unicode。 - nobody
谢谢。我正在编写一个VC++控制台应用程序,它打印出命令参数,但输出让我感到不舒服。 - James Ko
8个回答

112

编辑:如果你要写不能在默认语言环境中表示的文本,这种方法是不起作用的。 :-(

使用 std::wcout 代替 std::cout

wcout << ru << endl << en;

4
它只打印英文字符串。 俄语呢? - zed91
11
控制台不会启用Unicode。输出重定向是问题瓶颈,它停留在8位字符的传统遗留问题上。只有在正确的控制台字体加载到俄罗斯机器上时,它才能输出正确的文本。 - Hans Passant
1
请注意,如果您尝试在 Linux 控制台上打印此内容,您很可能会得到乱码字符,因为大多数 Linux 系统不使用 utf16 编码。 - Björn Lindqvist
1
那么当wcout不与UNICODE字符一起使用时,它是用来做什么的? - hfrmobile

20

我可以建议使用std::wcout吗?

那么,类似于这样:

std::cout << "ASCII and ANSI" << std::endl;
std::wcout << L"INSERT MULTIBYTE WCHAR* HERE" << std::endl;

您可能会在一个相关问题这里找到更多信息。


1
检查一下这个能否用俄语正常工作(复制粘贴)。对我来说不能。 - Euri Pinhollow
1
请参阅有关混合使用 coutwcout 的问题的线程。https://dev59.com/vmox5IYBdhLWcg3wznk0 - Jesse Chisholm

7

使用标准的C++工具无法便捷地打印宽字符串。

相反,您可以使用开源的 {fmt} 库便捷地打印Unicode文本。例如(https://godbolt.org/z/nccb6j):

#include <fmt/core.h>

int main() {
  const char en[] = "Hello";
  const char ru[] = "Привет";
  fmt::print("{}\n{}\n", ru, en);
}

打印

Привет
Hello

这需要在MSVC编译器中使用/utf-8编译选项进行编译。
与此相比,在Linux上向wcout写入:
wchar_t en[] = L"Hello";
wchar_t ru[] = L"Привет";
std::wcout << ru << std::endl << en;

可以将俄语文本转写为拉丁文(https://godbolt.org/z/za5zP8):

Privet
Hello

这个问题可以通过切换到使用UTF-8的语言环境来解决,但在Windows上存在类似的问题,不能仅通过标准设施来解决。
免责声明:我是{fmt}的作者。

2
#include <iostream>
using namespace std;
void main()
{
setlocale(LC_ALL, "Russian");
cout << "\tДОБРО ПОЖАЛОВАТЬ В КИНО!\n";
}

2
你可以通过提供代码说明来改进这个答案。 - James Elderfield
1
欢迎来到 Stack Overflow!虽然这段代码可能有助于解决问题,但它并没有解释为什么以及如何回答这个问题。提供这种额外的上下文将显著提高其长期价值。请编辑您的答案以添加说明,包括适用的限制和假设。 - Toby Speight

1

Windows的信息非常令人困惑。在编写Windows程序之前,您应该先从Unix/Linux学习C/C++概念。

wchar_t将字符存储为UTF-16,这是一种称为宽字符的固定16位内存大小,但wprintf()或wcout()永远无法正确打印非英文宽字符,因为没有控制台会输出UTF-16。 Windows将输出当前区域设置,而unix/linux将输出UTF-8,都是多字节的。因此,在打印之前,您必须将宽字符转换为多字节。unix命令wcstombs()在Windows上不起作用,请改用WideCharToMultiByte()。

首先,您需要使用记事本或其他编辑器将文件转换为UTF-8。然后在命令提示符控制台中安装字体,以便它能够读写您的语言,并将代码页更改为UTF-8,以便通过在命令提示符中键入“chcp 65001”来正确显示,而cygwin已经默认为UTF-8。以下是我在泰语中所做的。

#include <windows.h>
#include <stdio.h>

int main()
{
    wchar_t* in=L"ทดสอบ"; // thai language
    char* out=(char *)malloc(15);
    WideCharToMultiByte(874, 0, in, 15, out, 15, NULL, NULL);
    printf(out); // result is correctly in Thai although not neat
}

请注意,874=(泰语)操作系统中的代码页,15=字符串大小。
我的建议是,除非必要,否则避免将非英文宽字符打印到控制台上,因为这并不容易。

0

做法是将UTF-16 LE(默认Windows编码)转换为UTF-8,然后打印到控制台(首先使用chcp 65001切换代码页为UTF-8)。

将UTF-16转换为UTF-8非常简单。如果需要处理超过2个字节的字符,请使用此页面作为指南

short* cmd_s = (short*)cmd;
while(cmd_s[i] != 0)
{
    short u16 = cmd_s[i++];
    if(u16 > 0x7F)
    {
        unsigned char c0 = ((char)u16 & 0x3F) | 0x80; // Least significant
        unsigned char c1 = char(((u16 >> 6) & 0x1F) | 0xC0); // Most significant
        cout << c1 << c0; // Use Big-endian network order
    }
    else
    {
        unsigned char c0 = (char)u16;
        cout << c0;
    }
}

当然,你可以将它放在一个函数中,并扩展它以处理更广泛的字符(对于西里尔文应该足够了),但我想展示基本算法,并证明它并不难,你不需要任何库,只需要几行代码。

-1

您可以使用wprintf打印宽字符。

#include <iostream>

int main()
{
    wchar_t en[] = L"Hello";
    wchar_t ru[] = L"Привет"; //Russian language
    wprintf(en);
    wprintf(ru);
    return 0;
}

输出:

你好
Привет


-1
你可以使用一个普通的字符数组,实际上填充了UTF-8字符。这样应该允许混合使用不同语言的字符。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接